# 21. G1什么场景触发Full GC? Young GC?

# 标准答案

在 G1 垃圾回收器中,Full GC 通常在以下几种场景下发生:

  1. 老年代空间不足。
  2. 发生了无法处理的堆内存碎片。
  3. G1 的并发标记阶段失败,无法完成标记操作。

Young GC(年轻代垃圾回收)通常在以下场景下触发:

  1. 年轻代空间不足。
  2. 新对象的创建速度较快,导致年轻代频繁填满。

# 答案解析

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 垃圾回收器的区别有哪些?