🚀 深度解析 G1 收集器:Region 划分、大对象处理与 GC 流程全解

124 阅读5分钟

🎯 引言:G1 的“分而治之”哲学

G1 (Garbage-First) 收集器是现代 Java 虚拟机(JVM)默认的垃圾收集器,它的设计彻底颠覆了传统的“分代收集”理念,引入了Region(区域)的概念,实现了可预测的停顿时间

本篇博客将带你深入 G1 的底层架构,理解它是如何通过精妙的区域划分、智能的大对象处理和优化的 GC 流程,实现高吞吐量低延迟的完美平衡。


一、🌍 堆内存的基石:Region 划分与动态结构

G1 GC 的一切优势都建立在它的堆内存结构上:将整个 Java 堆划分为多个大小相等的独立区域(Region)

1. Region 的基本设定

特征细节说明
数量上限JVM 最多可以拥有 2048 个 Region
默认大小Region 大小通常等于 堆总大小 / 2048。例如,堆大小为 4096M,则每个 Region 大小约为 2M。
手动指定可以通过参数 -XX:G1HeapRegionSize 手动指定大小,但推荐 JVM 默认计算。

2. 动态灵活的分代概念

G1 虽然保留了年轻代老年代的概念,但它们不再是物理连续的内存块

  • 分代构成: 年轻代和老年代都是由 一组 Region 的集合 构成的,这些 Region 在堆内存中可以不连续
  • 功能动态变化: 一个 Region 可能在 Young GC 后被清空,随后被重新分配给老年代使用,这意味着 Region 的区域功能(年轻代/老年代)会动态变化

3. 年轻代的动态调整

G1 的新生代大小是动态调整的,以更好地满足停顿时间目标

  • 初始占比: 默认情况下,年轻代占堆内存的 5% (可通过 -XX:G1NewSizePercent 设置初始值)。
  • 最大限制: 无论如何增加,新生代的占比不会超过 60% (可通过 -XX:G1MaxNewSizePercent 调整)。
  • Eden/Survivor 比例: 新生代内部的 Eden 区和 Survivor 区(S0、S1)仍然遵循经典的 8:1:1 比例进行 Region 划分。

二、🐘 大对象的专门通道:Humongous 区

G1 对待大对象的方式非常特殊,它专门引入了 Humongous 区,目的是减轻老年代的负担。

1. 大对象的判定规则

  • 一个对象的大小超过了一个 Region 大小的 50% ,即被判定为大对象

    • 例如:如果 Region 大小是 2M,那么超过 1M 的对象就是大对象。

2. Humongous 区的作用

  • 分配位置: 大对象会被直接分配到 Humongous Region 中,而不会直接进入普通的老年代 Region。

  • 优势:

    • Humongous 区专门用于存放短期巨型对象
    • 节约了老年代的正常空间,避免老年代过快饱和而引发不必要的 GC 开销。
    • 如果大对象太大,它可能会横跨多个 Region 来存放。

3. 回收机制

  • 在正常的 Young GCMixed GC 中,Humongous 区的对象不会被回收
  • 只有在 Full GC 发生时,Humongous 区的对象才会与年轻代和老年代一起被一并回收

三、🔄 G1 垃圾收集的运作流程(四阶段)

G1 的垃圾收集运作流程,尤其是它的 并发标记 阶段,与 CMS 收集器有相似之处,但其最后的 筛选回收 阶段是独一无二的。

阶段停顿类型核心任务特点与深度解析
1. 初始标记STW (Pause)记录 GC Roots 直接引用的对象。速度极快,因为它只标记与 GC Roots 直接关联的对象。
2. 并发标记并发 (Concurrent)从 GC Roots 开始,遍历整个堆,标记所有存活对象。与应用程序线程同时运行,不造成停顿。此阶段会统计每个 Region 的存活对象比例
3. 最终标记STW (Remark)处理并发标记期间产生的新的引用变动(SATB)。再次暂停应用线程,确保所有存活对象被标记,完成对象图的精确化。
4. 筛选回收STW (Pause)根据回收价值和成本,制定回收计划并执行。这是 G1 “可预测停顿” 的核心实现:
1. 价值排序: 对所有 Region(包括年轻代和垃圾占比高的老年代)的回收价值预计成本进行排序。
2. 制定计划: 根据用户设定的最大停顿时间 (-XX:MaxGCPauseMillis),选择刚好在预算内能回收掉 Region 集合(Collection Set, CSet)。
3. 执行回收: 对 CSet 中的 Region 使用复制算法,将存活对象复制到新的空闲 Region。

💡 关键区别: G1 采用复制算法进行回收(即使是老年代),这使其在回收后几乎不会产生内存碎片,从而避免了 CMS 收集器回收后的“整理”步骤。


🔑 总结:G1 机制的核心优势

G1 收集器的成功,在于它将 可预测的低延迟 深度融入其底层设计:

  1. 分治管理: 通过 Region 划分,将大堆内存的回收压力分散到可控的小区域。
  2. 停顿预算: 筛选回收 阶段严格根据 -XX:MaxGCPauseMillis增量地选择要回收的 Region,确保单次停顿时间不会失控。
  3. 无碎片化: 采用 复制算法 进行回收,天然具备整理内存的能力,保持堆内存的整洁。

理解 G1 的 Region 结构和筛选回收机制,是进行高并发 Java 应用 GC 调优的关键!