# 21. G1什么场景触发Full GC? Young GC?
# 标准答案
在 G1 垃圾回收器中,Full GC 通常在以下几种场景下发生:
- 老年代空间不足。
- 发生了无法处理的堆内存碎片。
- G1 的并发标记阶段失败,无法完成标记操作。
Young GC(年轻代垃圾回收)通常在以下场景下触发:
- 年轻代空间不足。
- 新对象的创建速度较快,导致年轻代频繁填满。
# 答案解析
G1 垃圾回收器的工作目标是尽量减少停顿时间,同时优化吞吐量。它将堆划分为多个区域(Region),在垃圾回收时,它采用了分代的回收策略,其中包括年轻代(Young Generation)和老年代(Old Generation)。不同于传统的垃圾回收器,G1 通过增量化的方式来进行回收,以便更好地控制每次垃圾回收的停顿时间。
# 1. Young GC
Young GC 主要发生在年轻代,即 Eden 区域和 Survivor 区域。其目的是回收那些生命周期较短的对象。
- 触发条件:当年轻代的 Eden 区域没有足够空间来容纳新创建的对象时,G1 会触发一次 Young GC。这通常是因为对象存活的时间较长,或者新创建的对象速度过快。
- 过程:G1 会将存活的对象从 Eden 区域复制到 Survivor 区域,或者如果 Survivor 区域也满了,进一步转移到老年代。
- 频率:Young GC 的频率较高,主要受 Eden 区域的使用情况影响。
# 2. Full GC
Full GC 是指整个堆(年轻代和老年代)都参与的回收过程,它通常会造成较长时间的停顿,因为所有堆的回收操作都在停顿期间完成。
触发条件:
- 老年代空间不足:如果老年代的空间不足以容纳新晋升到老年代的对象,G1 会触发 Full GC。
- 并发标记失败:G1 进行并发标记时,如果并发标记阶段失败,不能完成标记工作,它就会转为 Full GC。
- 堆内存碎片:如果堆内存的碎片导致 G1 无法有效分配空间,也会触发 Full GC。
- 手动调用:如果开发者通过 JVM 参数或者在代码中手动触发,也可以引发 Full GC。
过程:Full GC 会标记和清除整个堆,包括年轻代和老年代。由于需要标记老年代的对象、清除垃圾并整理内存,因此相较于 Young GC,Full GC 会造成较长时间的停顿。
# 3. Full GC 和 Young GC 的区别
- 对象年龄:Young GC 主要回收的是年轻代中的短生命周期对象,而 Full GC 会涉及老年代的长生命周期对象。
- 停顿时间:Young GC 由于回收的是年轻代,通常停顿时间较短,而 Full GC 会涉及整个堆,因此停顿时间较长。
- 触发频率:Young GC 更为频繁,而 Full GC 由于涉及整个堆,触发频率较低,但通常会导致较长的停顿。
# 4. G1 的调优
通过 G1 的一些参数,可以影响 Full GC 和 Young GC 的触发条件和频率:
- -XX:MaxGCPauseMillis:设置 G1 垃圾回收的最大暂停时间目标。G1 会尽量调整 GC 的方式来满足该要求,但无法保证一定满足。
- -XX:InitiatingHeapOccupancyPercent:指定触发老年代 GC(混合 GC)时堆占用的百分比,默认值是 45%。可以根据需要调整这一值,以提前或延后触发 Full GC。
- -XX:G1HeapRegionSize:设置堆区域的大小,较小的区域可能会导致更频繁的垃圾回收,但更容易控制停顿时间。
- -XX:G1ReservePercent:设置 G1 在年轻代进行 GC 时为避免 Full GC 留下的空间保留百分比。
# 深入追问
- 如何在生产环境中监控 G1 的 GC 活动?如何确定是否存在频繁的 Full GC?
- 在高并发应用中,如何调优 G1 来平衡吞吐量和响应时间?
# 相关面试题
- G1 垃圾回收器的工作原理是什么?它如何实现低延迟和高吞吐量的平衡?
- G1 和 CMS 垃圾回收器的区别有哪些?