面试知识库
极高 困难

G1收集器原理#

一句话答案#

G1 将堆划分为等大 Region,优先回收垃圾最多的 Region(Garbage First),兼顾吞吐和停顿,JDK9+ 默认收集器。

核心要点

关键概念:

Remembered Set(RSet):

  • 每个 Region 都有一个 RSet,记录哪些其他 Region 引用了本 Region 的对象
  • 用途:Minor GC 时,不需要扫描整个老年代,只需扫描 RSet 中记录的引用
  • 代价:RSet 的维护有额外内存开销(约 10%~20%)

Card Table:

  • 老年代被划分为 512 字节的 Card,Card Table 记录哪些 Card 是”脏的”(被修改过)
  • 用于精确定位哪些老年代位置引用了年轻代对象

Humongous Region:

  • 大对象(>= Region 大小一半)直接分配到 Humongous Region
  • 跨多个 Region 连续分配
  • GC 时在 Old GC 阶段处理

G1 的停顿预测模型:

  • G1 记录每个 Region 的回收时间和可回收垃圾量
  • 根据 -XX:MaxGCPauseMillis 目标,选择在目标时间内能回收最多垃圾的 Region 集合
  • “Garbage First” 名字来自于优先回收垃圾占比最高的 Region

并发漏标:G1 为什么用 SATB(而非增量更新)?

  • G1 解决并发漏标走的是 SATB(Snapshot-At-The-Beginning)路线:写屏障记录”被删除/覆盖的旧引用”,破坏漏标条件②;按标记开始时的对象图快照标记,旧引用指向的白对象仍被标活。
  • 代价:会把”标记期间本已死亡”的对象也保活 → 产生浮动垃圾,留到下次 GC;好处是 remark 只需处理 SATB 缓冲区(量小),停顿短——这与 G1 追求可预测低停顿的目标一致。
  • 对比 CMS:CMS 用增量更新破坏条件①(记黑→白新增引用,remark 重扫黑对象,停顿偏长,无此类浮动垃圾)。两个漏标条件的完整推导见 垃圾回收算法 的「三色标记与并发漏标」主线。

G1 的完整 GC 流程:

1. Young GC(STW):

触发条件:Eden Region 被占满
流程:
  Eden Region + Survivor Region → 标记存活对象(借助 RSet 避免全堆扫描)
  → 存活对象复制到新的 Survivor Region
  → 年龄达到阈值的对象晋升到 Old Region
  → 回收原 Eden 和 Survivor Region

特点:
  全程 STW,但只涉及年轻代 Region,停顿较短(通常几毫秒到几十毫秒)
  G1 会动态调整 Eden/Survivor 的 Region 数量以满足停顿目标
plaintext

2. 并发标记周期(Concurrent Marking Cycle):

3. Mixed GC(混合回收):

触发条件:并发标记周期完成后自动触发
回收范围:所有 Young Region + 部分垃圾比例高的 Old Region
选择策略:优先选择垃圾最多的 Old Region(Garbage First 得名由来)
执行方式:分多轮执行,每轮都是 STW 的复制回收
控制参数:
  -XX:G1MixedGCCountTarget=8      # 分 8 轮 Mixed GC 逐步完成(默认)
  -XX:G1HeapWastePercent=5         # 可回收垃圾低于堆的 5% 时停止 Mixed GC
  -XX:G1OldCSetRegionThresholdPercent=10  # 每轮最多回收 10% 的 Old Region
plaintext

4. Full GC(退化回退):

触发条件:对象分配速度 > 回收速度(Allocation Failure / Evacuation Failure)
表现:JDK 9 及之前退化为单线程 Serial Old GC(停顿极长)
     JDK 10+ 支持并行 Full GC(G1 自身实现),但仍应尽量避免
调优目标:通过调整 MaxGCPauseMillis 和堆大小,确保 Mixed GC 能跟上分配速度
plaintext

G1 GC 模式对比:

维度Young GCMixed GCFull GC
触发条件Eden 满并发标记后分配失败
回收范围Young RegionYoung + 部分 Old整堆
是否 STW是(耗时长)
频率应避免
面试回答(2分钟版)

G1 是 JDK9 开始的默认垃圾收集器,最大的创新是把堆划分为约 2048 个大小相等的 Region(1-32MB),每个 Region 可以动态充当 Eden、Survivor、Old 或 Humongous 角色,不再是物理上连续的分代。G1 的核心思想是”Garbage First”,它维护一个停顿预测模型,记录每个 Region 的回收耗时和可回收垃圾量,根据 -XX:MaxGCPauseMillis 目标(默认 200ms)选择在目标时间内能回收最多垃圾的 Region 集合优先回收。跨 Region 引用通过 Remembered Set 解决,每个 Region 的 RSet 记录哪些其他 Region 引用了自己的对象,Minor GC 时不需要扫描整个老年代,只需扫描 RSet,代价是额外 10%-20% 的内存开销。大对象(大于等于 Region 一半)直接分配到 Humongous Region。G1 有三种 GC 模式:Young GC 在 Eden 满时触发只回收年轻代;当老年代占用达到 45% 会启动并发标记周期,分四步——初始标记借 Young GC 顺带完成、并发标记使用 SATB 算法遍历全堆、最终标记处理 SATB 缓冲区、清理统计各 Region 垃圾比例;标记完成后触发 Mixed GC,选择部分垃圾最多的老年代 Region 和全部年轻代一起回收,分多轮完成。如果回收速度跟不上分配速度,G1 会退化为 Full GC,这是需要调优避免的。

追问与易错

追问方向:

  • “G1 的 Region 大小怎么确定?”→ 1-32MB,默认堆/2048 个 Region
  • “Mixed GC 和 Full GC 的区别?”→ Mixed 选择部分 Region,Full 回退 Serial Old
  • “G1 怎么处理跨 Region 引用?”→ Remembered Set,卡表记录跨区引用

易错点:

  • ❌ “G1 不会 Full GC”——如果回收速度跟不上分配速度,会退化为 Full GC
  • ❌ 混淆 Young GC 和 Mixed GC——Mixed GC 包含部分老年代 Region