G1 收集器原理
候选人小孙在面试字节 P7 时,面试官问道:
"G1 收集器的核心设计是什么?"
小孙说:"把堆分成多个 Region..."面试官追问:"G1 的 Young GC 和 Mixed GC 有什么区别?"
小孙答不上来。面试官继续追问:"G1 怎么实现停顿时间目标的?"
小孙彻底卡住了...
一、核心问题:G1 收集器原理 🔴
1.1 问题拆解
1.2 ❌ 错误示范
候选人原话 A:"G1 不分代。"
问题诊断:G1 是逻辑分代的。它将堆划分为多个 Region,每个 Region 可以扮演不同的角色(Eden/Survivor/Old),而不是物理上的固定分代。
候选人原话 B:"G1 完全没有停顿。"
问题诊断:G1 仍然有 Stop-The-World 停顿(Young GC 和 Mixed GC),但停顿时间可控。
1.3 标准回答
P5 级别:Region 划分
G1 的 Region 设计:
G1 将堆划分为多个大小相等的 Region(默认 1MB,最大 32MB):
Humongous 区域:
超过 Region 大小 50% 的对象被称为 Humongous 对象,存储在 Humongous Region 中。Humongous 对象的回收优先级较低。
P6 级别:GC 类型
G1 的三种 GC 类型:
Young GC:
当 Eden Region 满了时触发。G1 将 Eden + Survivor Region 中的存活对象复制到新的 Survivor Region 或 Old Region。
Mixed GC:
G1 在 Young GC 时,追踪老年代的垃圾比例。如果老年代 Region 中的垃圾比例较高(通过 IVO - Initial Marked Value Offset),G1 将 Young GC 扩展为 Mixed GC,同时回收部分老年代 Region。
P7 级别:停顿时间目标的实现
MaxGCPauseMillis 的实现:
G1 不追求一次回收整个堆,而是通过增量回收的方式实现停顿时间目标:
实现原理:
G1 维护一个待回收 Region 列表
每次 GC 时,G1 选择回收价值最高的 Region(垃圾最多的 Region)
G1 计算每个 Region 的回收收益(回收后释放的空间 / 回收成本)
选择收益最高的 Region,直到达到停顿时间目标
Cocktail Table(鸡尾酒表):
G1 使用 Cocktail Table 追踪每个 Region 的 GC 信息:
通过历史数据,G1 预测下一次 GC 的时间,从而选择合适数量的 Region。
【面试官心理】 这道题我能问到 P7 级别,是因为 G1 的停顿时间控制是 GC 设计的核心技术。能说清 Cocktail Table 的候选人说明他理解了 G1 的自适应调优机制。
1.4 追问升级
追问:G1 什么时候会触发 Full GC?
G1 触发 Full GC 的情况:
- Mixed GC 回收的速度跟不上对象分配的速度
- Humongous 对象过多,导致没有足够的空间
- 元空间不足
二、生产调优 🟡
2.1 G1 调优参数
2.2 G1 vs CMS
面试加分点:能说出"JDK 12 引入了 G1 的 Abortable Preclean 优化,当 Young GC 发现 Mixed GC 无法在目标停顿时间内完成时,可以中止并发清理阶段,减少无谓的 CPU 消耗",说明他关注了 JDK 新特性。
面试陷阱:被问到"G1 的 Region 大小必须是 2 的幂次吗",很多人会说"不是"。准确答案是:必须是 2 的幂次,因为 G1 使用位运算计算 Region 索引。