G1(Garbage-First)垃圾回收器是Java虚拟机(JVM)中面向大内存、低延迟场景设计的垃圾回收器,自JDK 7u4正式推出,并在JDK 9后成为默认回收器。其核心原理结合了分区管理、并发标记和可预测停顿时间模型,以下从关键设计点展开说明:
🧩 一、核心设计思想
分区模型(Region-Based Heap)
G1将堆内存划分为多个大小相等的 Region(默认约2048个,每个1MB–32MB)。每个Region可动态充当以下角色:- Eden区:存放新对象。
- Survivor区:存放Minor GC后存活的对象。
- Old区:存放长期存活的对象。
- Humongous区:专存大小超过Region容量50%的大对象(如大数组)。
这种设计避免传统分代堆的物理隔离,实现内存分配的灵活性,并减少内存碎片。
垃圾优先(Garbage-First)策略
G1通过跟踪每个Region的回收价值(垃圾占比 × 回收速度),优先回收垃圾最多的Region,最大化单次回收效率。用户可通过-XX:MaxGCPauseMillis(默认200ms)设定最大停顿时间目标,G1据此动态调整回收范围。
🔁 二、工作流程:并发标记与混合回收
G1的回收过程分为四个阶段,其中仅并发标记阶段完全无停顿:
初始标记(Initial Marking)
- STW(暂停所有应用线程),标记GC Roots直接关联的对象。
- 借道Young GC:此阶段复用Young GC的暂停时间,几乎不增加额外开销。
并发标记(Concurrent Marking)
- 与用户线程并发执行,遍历对象图标记存活对象。
- 使用 SATB(Snapshot-At-The-Beginning)算法 记录标记开始时的对象快照,解决并发修改导致的“对象消失”问题。
最终标记(Final Marking)
- STW,处理SATB记录中的引用变更,确保标记完整性。
- 回收完全空闲的Region。
筛选回收(Evacuation)
- STW,基于回收价值排序Region,在停顿时间内复制存活对象到新Region(复制算法),并清空旧Region。
- 支持分批次回收(通过
-XX:G1MixedGCCountTarget控制批次),避免单次停顿过长。
⚙️ 三、关键技术机制
跨代引用处理:RSet(Remembered Set)
- 每个Region维护一个RSet,记录其他Region中指向本Region内对象的引用。
- 作用:避免全堆扫描。例如Young GC时,只需扫描Old区中RSet记录的卡表(Card Table),定位到老年代对新生代的引用。
大对象(Humongous)管理
- 大对象直接分配至连续Humongous Region,避免跨Region存储的复杂性。
- 回收时机:在Young GC或Mixed GC中随附属Region一并回收。
🔄 四、回收模式:Young GC 与 Mixed GC
| 模式 | 触发条件 | 回收范围 | 特点 |
|---|---|---|---|
| Young GC | Eden区满 | 仅新生代Region | STW,复制算法,频率高但停顿短 |
| Mixed GC | 老年代占比 ≥ 45%(默认) | 新生代 + 高价值老年代Region | 含并发标记阶段,可控制停顿时间 |
⚠️ Full GC触发条件:当Mixed GC中存活对象无空闲Region容纳时,退化为单线程Full GC(需极力避免)。
⚖️ 五、对比其他回收器
| 特性 | G1 | CMS | ZGC |
|---|---|---|---|
| 内存模型 | Region分区 | 连续分代 | 虚拟内存映射 |
| 停顿目标 | 可预测(200ms内) | 不可预测 | 亚毫秒级(<1ms) |
| 碎片处理 | 复制算法(自动整理) | 标记-清除(需压缩) | 无碎片 |
| 适用场景 | 堆内存 >6GB,兼顾吞吐与延迟 | 小堆(<6GB),低延迟 | 超大堆(TB级),极致延迟 |
🛠️ 六、调优建议
- 核心参数:
-XX:MaxGCPauseMillis=200:根据业务需求调整(过低易触发Full GC)。-XX:InitiatingHeapOccupancyPercent=45:调高可延迟Mixed GC触发。
- 避免Full GC:
- 增加堆内存,或降低大对象分配。
- 监控晋升失败(Promotion Failure)与疏散失败(Evacuation Failure)。
- Region大小优化:
堆较大时建议设置-XX:G1HeapRegionSize=4M(默认值计算为堆大小/2048)。
💎 总结
G1通过 Region分区 + 价值优先回收 + 并发标记 三大支柱,在大堆场景下平衡吞吐量与停顿可控性,成为JDK 9+的默认选择。其设计精髓在于:
✅ 空间维度:Region化解构堆内存,实现细粒度回收;
✅ 时间维度:SATB和RSet减少STW范围,并发标记提升效率;
✅ 策略维度:按回收价值动态选择目标,最大化单位时间收益。
对于追求更低延迟(如<10ms)或超大堆(>100GB)的场景,可评估ZGC或Shenandoah,但G1仍是多数生产环境的稳健之选。
