G1 垃圾收集器

作为 JVM 垃圾收集器的里程碑式设计,G1 旨在替代 CMS,解决CMS内存碎片不可控停顿等核心痛点,同时为现代大内存、多核处理器环境提供更平衡的吞吐量与低延迟表现。


一、核心设计思想

1. 分区(Region)

  • 堆不再物理划分为固定的年轻代(Young)、老年代(Old),而是划分为 大小相等 的 Region(默认约 2048 个,每个 Region 大小为 1MB~32MB)。
  • Region 类型动态变化:可随时作为 Eden、Survivor、Old 或 Humongous(存放大对象)区使用。
  • 优势
    • 避免 CMS 的内存碎片问题:通过 复制算法(年轻代)和 标记-整理算法(老年代)在 Region 间移动对象。
    • 更精细的内存管理:可针对部分 Region 回收,避免全堆扫描。

2. 停顿预测

  • 核心目标:满足用户设定的 最大停顿时间目标-XX:MaxGCPauseMillis,默认 200ms)。
  • 实现方式:
    • 跟踪每个 Region 的回收价值(可释放空间)与回收成本(复制对象的时间)。
    • 每次回收优先选择 垃圾最多(Garbage-First) 的 Region 集合,在有限时间内释放最大内存。

二、工作流程

1. 年轻代收集(Young GC)

  • 触发条件:Eden 区占满时触发。
  • 过程(STW):
    1. 扫描 GC Roots,标记 Eden 和 Survivor 区的存活对象。
    2. 存活对象复制到新的 Survivor Region(晋升)或 Old Region(达到年龄阈值)。
    3. 清空原有 Eden/Survivor Region,加入空闲列表。
  • 特点:并行多线程执行,停顿时间较短。

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

目标:识别老年代 Region 中的垃圾,为混合收集做准备。
阶段(类似 CMS,但基于 Region):

  1. 初始标记(STW)
    • 标记 GC Roots 直接关联的对象。
    • 借道 Young GC:在 Young GC 的 STW 期间同步完成,成本极低。
  2. 根区域扫描
    • 扫描 Survivor Region(根区域)到老年代的引用。
    • 需在下次 Young GC 前完成(否则阻塞 Young GC)。
  3. 并发标记(Concurrent Mark)
    • 遍历堆,标记所有存活对象(使用 SATB 算法 处理并发修改)。
  4. 最终标记(STW)
    • 处理 SATB 缓冲区引用,修正并发标记期间的变动。
  5. 筛选回收(STW)
    • 统计各 Region 存活对象占比,排序回收价值。
    • 释放完全空闲的 Region,更新空闲列表。

3. 混合收集(Mixed GC)

  • 触发条件:老年代占用达到阈值(-XX:InitiatingHeapOccupancyPercent,默认 45%)。
  • 过程
    • 选择一批 高收益的老年代 Region + 所有年轻代 Region 进行回收。
    • 采用 复制算法:将存活对象移动到空闲 Region(整理内存)。
  • 多次执行:直到回收足够内存或达到 MaxGCPauseMillis 目标。

4. Full GC(失败回退)

  • 触发条件
    • 晋升失败(复制对象时目标 Region 不足)。
    • 并发标记周期未完成时堆已占满。
  • 行为:退化为单线程的 Serial Old GC(Mark-Compact),停顿极长!
    需优化避免 Full GC

三、关键技术

1. SATB(Snapshot-At-The-Beginning)

  • 解决并发标记漏标问题
    • 初始标记时对堆做快照,后续标记基于此快照。
    • 并发期间被修改的引用记录到 SATB 缓冲区,最终标记阶段再扫描。
  • 优势:比 CMS 的增量更新更高效,减少重新标记工作量。

2. 记忆集(Remembered Set, RSet)

  • 问题:跨 Region 引用如何避免全堆扫描?
  • 解决
    • 每个 Region 有一个 RSet,记录 其他 Region 指向本 Region 的引用
    • 写屏障(Write Barrier)监控引用修改,更新 RSet。
  • 作用:回收时只需扫描 RSet,避免遍历整个老年代。

3. 收集集合(Collection Set, CSet)

  • 每次 GC 回收的 Region 集合(Young GC 含 Eden+Survivor,Mixed GC 额外加入老年代 Region)。
  • 选择策略:优先选择垃圾比例高(Garbage-First)、回收耗时低的 Region。

四、核心参数与调优

参数说明
-XX:+UseG1GC启用 G1 收集器
-XX:MaxGCPauseMillis=200目标最大停顿时间(软目标,非强制保证)
-XX:InitiatingHeapOccupancyPercent=45触发并发标记周期的堆占用阈值
-XX:G1HeapRegionSize=N手动设置 Region 大小(1MB~32MB,需为 2 的幂)
-XX:G1NewSizePercent / -XX:G1MaxNewSizePercent年轻代占比范围(默认 5%~60%)
-XX:G1MixedGCLiveThresholdPercent=85混合收集中,Old Region 存活对象占比 低于此值 才加入 CSet
-XX:G1MixedGCCountTarget=8混合 GC 分几次执行完(避免单次停顿过长)
-XX:G1HeapWastePercent=5可容忍的堆浪费比例,达到则停止混合 GC

调优方向

  1. 优先调整 MaxGCPauseMillis:根据应用需求设定合理值(过低会导致频繁 GC)。
  2. 监控避免 Full GC
    • 增加堆大小或降低 InitiatingHeapOccupancyPercent
    • 优化对象分配速率(减少大对象、调整晋升年龄)。
  3. 关注 RSet 开销:过高的写屏障负担可能拖慢应用(通过 -XX:+G1SummarizeRSetStats 分析)。

五、G1 vs CMS:核心优势对比

特性CMSG1
内存布局连续分代(Young/Old)分区模型(Region)
算法标记-清除(产生碎片)复制+标记-整理(无碎片)
停顿控制不可预测可预测(软实时目标)
大堆处理性能下降明显更适合大堆(4GB~数十GB)
Full GC 风险高(碎片+并发失败)低(设计规避,仍有回退)
适用版本Java 1.4~8(14 移除)Java 7u4+,JDK 9+ 默认收集器

六、缺点

  1. 内存占用更高
    • RSet 和 Card Table 占用额外空间(约堆的 10%~20%)。
  2. 写屏障开销
    • 监控引用修改有 CPU 成本(尤其引用密集型应用)。
  3. 小堆不适用
    • Region 管理和元数据开销在小堆(<4GB)中占比过高。

七、优化与替代方案

  • ZGC / Shenandoah
    新一代超低停顿(亚毫秒级)收集器,适用于 TB 级堆。核心创新:
    • ZGC:染色指针 + 并发压缩
    • Shenandoah:并发复制 + 读屏障
  • G1 仍在优化
    JDK 12+ 引入特性如:
    • 及时返回未用内存(-XX:+G1UncommitDelay)。
    • 并行 Full GC(JDK 10+,避免单线程停顿)。

总结

G1 是面向服务端应用的里程碑式垃圾收集器,它通过分区、停顿预测和并发标记-整理算法,在延迟可控性、吞吐量和堆容量之间取得了平衡:

  1. ✅ 解决 内存碎片 问题
  2. ✅ 提供 可预测的停顿时间
  3. ✅ 适应 大内存场景(4GB~数十GB)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值