📌PDF:大白话说Java面试题 — 02-JVM篇
第7题:Young GC 和 Full GC 分别采用什么算法
📚回答:
- 核心概念:
JVM 的垃圾回收机制针对不同代(年轻代和老年代)采用了不同的算法,以提高回收效率和减少性能开销。以下是 Young GC 和 Full GC 使用的具体算法及其特点:
1. Young GC 的算法:标记-复制(Mark-Copy)
定义:
- 将年轻代划分为一个较大的 Eden 区和两个较小的 Survivor 区(From 和 To)。
- 每次只使用 Eden 区和其中一个 Survivor 区,当内存不足时,触发 Young GC:
- 标记存活对象(即未被回收的对象)。
- 将存活对象从 Eden 区和 From Survivor 区复制到 To Survivor 区。
- 清理 Eden 区和 From Survivor 区的所有空间。
- 交换 From 和 To Survivor 区的角色,为下一次 GC 做准备。
优点:
- 高效清理短生命周期的对象,避免内存碎片化问题。
缺点:
- 需要额外的 Survivor 区空间,导致内存利用率较低。
💡代码示例:
以下伪代码展示了标记-复制算法的基本流程:
// Eden 区和 Survivor 区Object[]eden=newObject[10];Object[]survivorFrom=newObject[5];Object[]survivorTo=newObject[5];// 标记存活对象并复制到 To Survivor 区for(Objectobj:eden){if(isAlive(obj)){copyToSurvivor(survivorTo,obj);}}// 清理 Eden 区和 From Survivor 区eden=newObject[10];// 清空 Eden 区survivorFrom=newObject[5];// 清空 From Survivor 区2. Full GC 的算法:标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)
标记-清除(Mark-Sweep):
- 过程:
- 标记所有存活对象。
- 统一回收未标记的对象(垃圾对象)。
- 优点:
- 实现简单,适合一次性清理大量垃圾对象。
- 缺点:
- 容易产生内存碎片,影响后续分配大对象的效率。
- 过程:
标记-整理(Mark-Compact):
过程:
- 标记所有存活对象。
- 将所有存活对象向内存的一端移动,压缩内存空间。
- 清理边界以外的空间。
优点:
- 避免内存碎片化问题,适合频繁分配大对象的场景。
缺点:
- 整理过程需要额外的时间开销,性能略低于标记-清除。
💡源码解析:
HotSpot VM的SerialGC和ParallelGC默认使用标记-整理算法,而CMS使用标记-清除算法。具体实现可以参考GenCollectedHeap和ConcurrentMarkSweepGeneration模块。
3. 对比总结
| 算法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 标记-复制 | 年轻代(短生命周期对象) | 高效清理垃圾,无内存碎片 | 需要额外的 Survivor 区,内存利用率低 |
| 标记-清除 | 老年代(少量垃圾对象) | 实现简单,适合一次性清理大量垃圾 | 易产生内存碎片 |
| 标记-整理 | 老年代(频繁分配大对象) | 避免内存碎片,适合长期运行的应用 | 整理过程耗时较长 |
💡面试官视角:
- 面试官可能会问“为什么年轻代使用标记-复制算法?”答:因为年轻代中大多数对象是短生命周期的,标记-复制算法能高效清理垃圾且无碎片问题。
- 面试官可能会追问“标记-清除和标记-整理的区别是什么?”答:标记-清除直接回收垃圾,容易产生碎片;标记-整理会压缩内存,避免碎片但耗时更长。