G1垃圾收集器通过Region分区和混合回收机制,平衡吞吐与延迟,支持大堆内存。利用SATB算法和记忆集减少停顿,适用延迟敏感场景。调优可控停顿,但需注意内存占用与Full GC风险。
一、G1 的设计目标
G1 是 JDK 7 引入的面向服务端应用的垃圾收集器,核心目标为:
- 可预测的停顿时间:通过设置
-XX:MaxGCPauseMillis(默认 200ms)控制 GC 停顿时间。 - 大堆内存友好:支持 TB 级堆内存,避免传统分代收集器的全堆扫描问题。
- 平衡吞吐与延迟:在较高吞吐量和较低延迟之间取得平衡。
二、G1 的核心设计
1. Region 分区
-
堆划分:将堆内存划分为多个大小相等的 Region(默认约 2048 个,每个 Region 大小 1MB~32MB,通过
-XX:G1HeapRegionSize指定)。 -
动态分代:
- Region 可以是 Eden、Survivor、Old 或 Humongous(大对象区,存储大小超过 Region 50% 的对象)。
- 分代逻辑上存在,物理上不连续,动态分配 Region 用途。
2. SATB(Snapshot-At-The-Beginning)算法
- 并发标记基础:在标记开始时对堆内存“拍照”,记录存活对象快照。
- 处理并发修改:通过写屏障(Write Barrier)记录并发期间被修改的引用,确保标记准确性。
3. Remembered Set(记忆集)
- 跨 Region 引用跟踪:每个 Region 维护一个记忆集(RSet),记录其他 Region 对当前 Region 的引用。
- 避免全堆扫描:GC 时仅需扫描 RSet,而非整个堆,提升效率。
三、G1 的工作流程
G1 的垃圾回收分为两个阶段:
- Young GC:回收年轻代(Eden + Survivor)的 Region。
- Mixed GC:混合回收年轻代和部分老年代 Region(需满足阈值条件)。
1. Young GC 流程
-
触发条件:Eden 区 Region 耗尽时触发。
-
复制存活对象:
- 将 Eden 和 Survivor 区存活对象复制到新的 Survivor Region。
- 年龄计数器递增,达到阈值(默认 15)的对象晋升到 Old Region。
-
更新 RSet:记录跨 Region 引用。
2. Mixed GC 流程
-
触发条件:
- 堆内存使用率达到阈值(默认 45%,通过
-XX:InitiatingHeapOccupancyPercent调整)。 - 需要回收老年代 Region 以释放空间。
- 堆内存使用率达到阈值(默认 45%,通过
-
全局并发标记:
- 初始标记(Initial Mark,STW):标记 GC Roots 直接可达的对象(与 Young GC 同步触发)。
- 根区域扫描(Root Region Scanning):扫描 Survivor Region 的引用。
- 并发标记(Concurrent Mark):遍历堆,标记所有存活对象。
- 最终标记(Final Mark,STW):处理 SATB 记录,修正标记结果。
- 清理阶段(Cleanup,STW):统计各 Region 的存活对象比例,选择回收价值高的 Region。
-
混合回收(Mixed Collection,STW):
- 回收选中的年轻代和老年代 Region。
- 重复多次 Mixed GC 直到满足堆空间释放目标。
四、G1 的关键优化机制
1. 增量回收
- 分批次回收:每次 Mixed GC 仅回收部分 Region,避免一次性全堆回收的长停顿。
- 停顿可控:通过
-XX:MaxGCPauseMillis动态调整回收 Region 数量。
2. 并行与并发
- 并行阶段:Young GC 和 Mixed GC 的 STW 阶段使用多线程加速。
- 并发阶段:全局并发标记的大部分操作与应用线程并发执行。
3. 内存整理
- 局部整理:回收 Region 时,将存活对象复制到空闲 Region,减少内存碎片。
- Full GC 兜底:当 Mixed GC 无法满足内存需求时,触发 Full GC(标记-整理算法,需避免)。
五、G1 的优缺点
优点
- 可预测停顿:通过参数控制目标停顿时间。
- 大堆高效:Region 分区减少全堆扫描开销。
- 内存碎片少:局部整理降低碎片化风险。
缺点
- 内存占用高:维护 RSet 和卡表占用额外内存(约堆的 10%~20%)。
- 吞吐量略低:相比 Parallel 回收器,吞吐量降低约 10%。
- Full GC 风险:并发标记失败或晋升失败时触发 Full GC。
六、G1 调优参数
| 参数 | 作用 | 示例值 |
|---|---|---|
-XX:+UseG1GC | 启用 G1 回收器 | 默认不启用 |
-XX:MaxGCPauseMillis | 目标最大停顿时间(毫秒) | 200(默认) |
-XX:InitiatingHeapOccupancyPercent | 触发 Mixed GC 的老年代占用阈值(百分比) | 45(默认) |
-XX:G1HeapRegionSize | 指定 Region 大小 | 16m(16MB) |
-XX:G1NewSizePercent | 年轻代初始占比(堆百分比) | 5(默认) |
-XX:G1MaxNewSizePercent | 年轻代最大占比(堆百分比) | 60(默认) |
-XX:ConcGCThreads | 并发标记阶段的线程数 | 根据 CPU 核数调整 |
七、适用场景
- 大堆内存应用:堆内存超过 6GB,传统分代收集器效率下降。
- 延迟敏感场景:需避免长时间停顿(如实时交易系统)。
- 内存碎片问题:老年代碎片化导致 Full GC 频繁。
八、G1 与其他回收器的对比
| 回收器 | 停顿时间 | 吞吐量 | 内存占用 | 适用场景 |
|---|---|---|---|---|
| G1 | 可控(亚秒级) | 中等 | 较高 | 大堆、平衡吞吐与延迟 |
| CMS | 低(但碎片导致不稳定) | 中等 | 低 | 老年代低延迟,堆较小 |
| Parallel | 高 | 高 | 低 | 吞吐优先,堆较小 |
| ZGC | 极低(亚毫秒级) | 中等 | 高 | 超大堆(TB 级)、极致低延迟 |
九、总结
G1 通过 Region 分区、SATB 标记和 混合回收 机制,实现了大堆内存下的高效垃圾回收,兼顾吞吐量和延迟。调优时需关注目标停顿时间、堆占用阈值和 Region 大小,结合监控工具(如 GC 日志、JVisualVM)分析瓶颈。对于追求极致低延迟的超大堆场景,可考虑 ZGC 或 Shenandoah,但 G1 仍是大多数生产环境的稳健选择。