G1垃圾收集器是如何工作的?

目录

[一、G1 的核心设计基础](#一、G1 的核心设计基础)

[1. 堆内存的 Region 化划分(逻辑分区,动态标记)](#1. 堆内存的 Region 化划分(逻辑分区,动态标记))

[2. 垃圾优先回收策略(核心设计目标)](#2. 垃圾优先回收策略(核心设计目标))

[3. 核心回收算法(无内存碎片,兼顾效率)](#3. 核心回收算法(无内存碎片,兼顾效率))

[4. 前置概念:GC Roots 与跨代引用管理](#4. 前置概念:GC Roots 与跨代引用管理)

[二、G1 的完整工作流程(三类 GC,分层执行)](#二、G1 的完整工作流程(三类 GC,分层执行))

[流程 1:Young GC(新生代回收)------ 高频、短停顿、纯 STW](#流程 1:Young GC(新生代回收)—— 高频、短停顿、纯 STW)

[1. 触发条件](#1. 触发条件)

[2. 完整执行步骤(多线程并行,全程 STW,毫秒级)](#2. 完整执行步骤(多线程并行,全程 STW,毫秒级))

[3. 关键特点](#3. 关键特点)

[流程 2:Mixed GC(混合回收)------ 核心流程、可预测停顿、部分并发 + 部分 STW](#流程 2:Mixed GC(混合回收)—— 核心流程、可预测停顿、部分并发 + 部分 STW)

[1. 触发条件](#1. 触发条件)

[2. 完整执行步骤(4 个阶段:2 个 STW+2 个并发,停顿可控)](#2. 完整执行步骤(4 个阶段:2 个 STW+2 个并发,停顿可控))

[阶段 1:初始标记(Initial Mark)------ STW,极短(复用 Young GC 的 STW)](#阶段 1:初始标记(Initial Mark)—— STW,极短(复用 Young GC 的 STW))

[阶段 2:并发标记(Concurrent Mark)------ 纯并发,不 STW,耗时最长](#阶段 2:并发标记(Concurrent Mark)—— 纯并发,不 STW,耗时最长)

[阶段 3:最终标记(Final Mark)------ STW,短时间](#阶段 3:最终标记(Final Mark)—— STW,短时间)

[阶段 4:筛选回收(Live Data Counting and Evacuation)------ STW,核心优化,停顿可预测](#阶段 4:筛选回收(Live Data Counting and Evacuation)—— STW,核心优化,停顿可预测)

[3. 关键特点](#3. 关键特点)

[流程 3:Full GC(兜底回收)------ 极少触发、长时间 STW、需彻底避免](#流程 3:Full GC(兜底回收)—— 极少触发、长时间 STW、需彻底避免)

[1. 触发条件](#1. 触发条件)

[2. 执行逻辑](#2. 执行逻辑)

[3. 关键特点](#3. 关键特点)

[三、G1 的核心工作联动逻辑](#三、G1 的核心工作联动逻辑)

[四、G1 的核心优化机制(对比 CMS,全维度升级)](#四、G1 的核心优化机制(对比 CMS,全维度升级))

[五、G1 核心配置参数](#五、G1 核心配置参数)

六、核心总结

核心记忆点

G1(Garbage-First)是 JDK9 + 默认的整堆低延迟垃圾收集器 ,核心设计目标是在大内存场景下实现可预测的 GC 停顿时间 ,同时兼顾吞吐量。它打破了传统 GC「新生代 + 老年代物理划分」的模式,采用Region 化整堆管理 ,结合并发标记、复制回收、垃圾优先筛选三大核心技术,自身实现新生代 + 老年代的全堆回收,彻底解决了 CMS 的内存碎片、并发失败等问题。

G1 的工作核心围绕Region 内存管理 + 三类分层 GC 流程(Young GC/Mixed GC/Full GC)展开,其中 Mixed GC是 G1 的设计精髓,也是实现停顿可预测的关键;Full GC 为兜底场景,生产中几乎不会触发。

一、G1 的核心设计基础

G1 的所有工作流程都基于Region 化堆内存管理 和垃圾优先回收策略,这是它与经典 GC(CMS/Parallel)最本质的区别,也是理解其工作原理的前提。

1. 堆内存的 Region 化划分(逻辑分区,动态标记)

G1 将整个 Java 堆划分为多个大小相等的独立内存块(Region),替代了传统 GC 的新生代、老年代物理分区,核心特点:

  • Region 大小统一 :默认 1MB~32MB(2 的幂次),JVM 会根据堆总大小自适应调整 (如堆 16G 则 Region 为 4M/8M),可通过-XX:G1HeapRegionSize手动指定;

  • 类型动态标记 :每个 Region 无固定的代别,可动态标记 为不同类型,运行中可相互转换,核心类型包括:

    Region 类型 核心作用 对应传统区域
    Eden 存储新创建的普通对象 新生代 Eden 区
    Survivor 存储 Young GC 后的存活对象 新生代 Survivor 区
    Old 存储新生代晋升的长命对象、大对象 老年代
    Humongous 存储超大对象(超过 Region 大小 50%),由连续多个 Region 组成 老年代大对象区
    Free 空闲 Region,用于分配新对象或复制存活对象 无
  • 逻辑分代 :G1 通过 Region 类型标记实现逻辑上的新生代 / 老年代,而非物理隔离,新生代由所有 Eden+Survivor Region 组成,老年代由所有 Old+Humongous Region 组成,占比可动态调整(新生代 5%~60%)。

2. 垃圾优先回收策略(核心设计目标)

G1 的「Garbage-First」体现在优先回收垃圾比例最高的 Region,核心逻辑:

  1. 每次回收前,G1 会统计每个 Region 的垃圾比例(垃圾占比 = 1 - 存活对象占比);
  2. 按垃圾比例从高到低为 Region 排序,形成回收候选列表;
  3. 结合用户指定的最大停顿时间 (-XX:MaxGCPauseMillis,默认 200ms),计算可回收的 Region 数量(垃圾比例越高,回收效率越高,优先选择);
  4. 仅回收筛选后的 Region,保证总 GC 停顿时间不超过阈值。

这一策略让 G1 在有限的 STW 时间内释放最多的内存 ,实现了停顿时间的可预测性,也是 G1 适配大内存(8G~64G)的关键。

3. 核心回收算法(无内存碎片,兼顾效率)

G1 全程采用复制算法完成垃圾回收,替代了 CMS 的标记 - 清除算法,核心特点:

  • 回收时,将待回收 Region 中的存活对象 复制到空闲的 Free Region;
  • 复制完成后,清空原 Region 并标记为 Free,用于后续对象分配;
  • 最终存活对象会被集中存储在连续的 Region 中 ,无任何内存碎片,彻底解决了 CMS 的大对象分配失败问题。

4. 前置概念:GC Roots 与跨代引用管理

G1 通过 **SATB(Snapshot-At-The-Beginning,开始快照)机制管理跨代引用(如老年代对象引用新生代对象),配合卡表(Card Table)** 记录引用变动,避免全堆扫描,大幅降低 GC 开销,这一机制会在并发标记阶段核心使用。

二、G1 的完整工作流程(三类 GC,分层执行)

G1 的 GC 流程分为Young GC(新生代回收) 、Mixed GC(混合回收) 、Full GC(兜底回收)三类,三者为分层执行关系:

  • Young GC:高频基础流程,仅回收新生代 Region,毫秒级 STW,是 G1 最常触发的 GC;
  • Mixed GC :核心流程,替代传统 Major GC/Full GC,同时回收新生代所有 Region + 部分老年代 Region,部分并发 + 部分 STW,停顿时间可控;
  • Full GC:兜底异常流程,仅在 Mixed GC 无法释放足够内存时触发,单线程 STW,生产中需彻底避免。

流程 1:Young GC(新生代回收)------ 高频、短停顿、纯 STW

G1 的 Young GC 与经典新生代 GC(ParNew)核心逻辑一致,仅回收所有 Eden Region + 非空 Survivor Region,基于 Region 粒度采用复制算法,是 G1 最常触发的 GC(每秒数次)。

1. 触发条件

Eden Region 内存不足,无法为新创建的普通对象分配内存(与传统 Young GC 触发条件完全一致,是程序运行的自然结果)。

2. 完整执行步骤(多线程并行,全程 STW,毫秒级)

G1 的 Young GC 为纯 STW 操作,但多线程并行执行,停顿时间极短,步骤如下:

  1. 暂停所有用户线程(STW):触发 Young GC 时,立即暂停所有业务线程,避免引用关系变动;
  2. 标记新生代 GC Roots :遍历虚拟机栈、本地方法栈等,标记新生代的 GC Roots ,同时通过卡表 标记老年代指向新生代的跨代引用(这是新生代存活对象的 "入口");
  3. 复制存活对象 :采用复制算法,将所有 Eden Region + 非空 Survivor Region 中的存活对象,复制到空闲的 Free Region :
    • 年龄未达晋升阈值的对象 → 复制到新的 Survivor Region;
    • 年龄达阈值(默认 15,-XX:MaxTenuringThreshold)的对象 → 复制到Old Region;
  4. 重置 Region 状态 :清空原 Eden/Survivor Region,将其标记为Free Region,用于后续新对象分配;
  5. 恢复用户线程:完成所有操作后,恢复业务线程,Young GC 结束。
3. 关键特点
  • 触发频率极高(程序运行中持续触发),但 STW 时间毫秒级(通常<50ms),对业务几乎无感知;
  • 回收后无内存碎片,新生代 Region 规整,为后续对象分配提供连续空间;
  • 无需并发执行,纯 STW 即可保证效率,因为新生代对象 "朝生夕死",存活比例极低,复制开销极小。

流程 2:Mixed GC(混合回收)------ 核心流程、可预测停顿、部分并发 + 部分 STW

Mixed GC 是 G1 的设计精髓 ,也是替代传统 CMS 老年代回收 + Full GC 的核心流程,同时回收新生代所有 Region + 部分老年代 Region ,是 G1 唯一会执行并发标记的 GC 流程。

Mixed GC 的核心是 **「并发标记(不 STW)+ 筛选回收(可控 STW)」**,既保证了低延迟,又能回收老年代的垃圾,是 G1 实现 "大内存 + 可预测停顿" 的关键。

1. 触发条件

老年代 Region 的整体使用率达到阈值 (默认 45%,-XX:InitiatingHeapOccupancyPercent配置),即堆的整体内存使用率达标(G1 以整堆使用率判断,而非单独老年代)。

注意:Mixed GC不会主动触发 ,而是由 JVM 根据堆内存使用情况自动判断,触发频率远低于 Young GC(几分钟 / 几小时一次)。

2. 完整执行步骤(4 个阶段:2 个 STW+2 个并发,停顿可控)

Mixed GC 分为初始标记、并发标记、最终标记、筛选回收 4 个阶段,其中2 个阶段纯并发(不 STW) ,2 个阶段短 STW ,且 STW 时间严格控制在MaxGCPauseMillis范围内。

阶段 1:初始标记(Initial Mark)------ STW,极短(复用 Young GC 的 STW)
  • 核心作用 :标记整堆的 GC Roots 直接关联对象(包括新生代 + 老年代),同时标记老年代指向新生代的跨代引用;
  • 触发优化 :此阶段无需单独触发 STW ,而是复用一次 Young GC 的 STW 时间完成(G1 的重要优化,减少额外停顿);
  • 执行结果:得到整堆存活对象的 "根集",为后续并发标记做基础,STW 时间<10ms。
阶段 2:并发标记(Concurrent Mark)------ 纯并发,不 STW,耗时最长
  • 核心作用 :从初始标记的根集对象出发,全量遍历整堆所有 Region 的引用链 ,标记所有存活对象,同时统计每个 Region 的垃圾比例;
  • 执行逻辑 :恢复用户线程,GC 线程与业务线程并行执行 ,完成两个核心工作:
    1. 遍历所有 Region(Eden/Survivor/Old/Humongous),为所有存活对象打上标记;
    2. 统计每个 Region 的存活对象占比 ,计算垃圾比例,并按垃圾比例从高到低排序,生成回收候选列表;
  • 关键特点 :
    1. 此阶段是 Mixed GC 耗时最长的阶段,但无任何 STW,对业务无影响;
    2. 会产生浮动垃圾(并发阶段用户线程新创建的对象,未被标记,需等到下一次 GC 回收),但 G1 对浮动垃圾无额外处理,不影响回收流程;
    3. 通过SATB 机制处理并发阶段的引用变动,保证标记的准确性。
阶段 3:最终标记(Final Mark)------ STW,短时间
  • 核心作用 :修正并发标记阶段的标记偏差 ,处理并发阶段因用户线程操作导致的引用变动记录;
  • 执行逻辑 :暂停所有用户线程,多线程并行处理SATB 队列 (存储并发阶段所有引用修改、对象新建的记录),补充标记未被遍历的存活对象,同时最终确认老年代 Region 的回收候选列表;
  • 关键特点 :仅处理变动记录,不做全量遍历,STW 时间毫秒级(通常<50ms)。
阶段 4:筛选回收(Live Data Counting and Evacuation)------ STW,核心优化,停顿可预测

这是 G1 实现 **「停顿时间可预测」的核心阶段,也是 Mixed GC 的最后一步,核心是"按需选择 Region,可控 STW 回收"**。

  • 核心作用:根据最大停顿时间,筛选待回收的 Region,采用复制算法完成新生代 + 部分老年代的回收;
  • 执行逻辑 (全程 STW,多线程并行):
    1. 筛选 Region :结合-XX:MaxGCPauseMillis设置的最大停顿时间,从回收候选列表 中选择垃圾比例最高的老年代 Region ,同时加入所有新生代 Region,计算总回收耗时,保证不超过阈值;
    2. 复制存活对象 :将所有待回收 Region(新生代 + 筛选后的老年代)中的存活对象,复制到空闲的 Free Region,按对象年龄标记为新的 Survivor/Old Region;
    3. 重置 Region 状态:清空所有待回收 Region,将其标记为 Free Region,用于后续对象分配;
  • 关键特点 :
    1. 仅回收筛选后的部分老年代 Region,而非全量老年代,严格控制 STW 时间;
    2. 全程采用复制算法,无内存碎片,回收后堆内存规整;
    3. 一次 Mixed GC 后,若老年代使用率仍高,JVM 会连续触发多次 Mixed GC,逐步回收老年代垃圾,直到使用率降至阈值以下。
3. 关键特点
  • Mixed GC 是 G1唯一会回收老年代的 GC 流程,替代了传统的 Major GC/Full GC;
  • 整体流程 **"2 个短 STW+2 个纯并发"**,STW 总时间严格控制在用户指定的阈值内;
  • 回收效率高,优先回收垃圾比例高的 Region,在有限时间内释放最多内存。

流程 3:Full GC(兜底回收)------ 极少触发、长时间 STW、需彻底避免

G1 的 Full GC 是异常兜底场景 ,仅在 Mixed GC 无法释放足够内存时触发,生产环境中若频繁触发 Full GC,说明堆配置或 G1 调参存在严重问题。

1. 触发条件
  1. Mixed GC 筛选回收后,空闲 Region 仍不足,无法分配新对象 / 晋升对象;
  2. 超大对象无法找到连续的 Humongous Region;
  3. 显式调用System.gc()(可通过-XX:+DisableExplicitGC禁用);
  4. G1 并发标记阶段出现异常,导致标记失败。
2. 执行逻辑

G1 的 Full GC 采用单线程标记 - 整理算法,全程 STW,执行效率极低,步骤如下:

  1. 暂停所有用户线程,全量遍历整堆,标记所有存活对象;
  2. 单线程将所有存活对象向内存一端移动整理,使空闲内存连续;
  3. 清空无用对象的内存,恢复用户线程。
3. 关键特点
  • STW 时间秒级甚至十几秒,对业务影响极大,是生产环境的 "性能杀手";
  • G1 会尽最大努力避免触发 Full GC,正常配置下,生产环境中几乎不会出现。

三、G1 的核心工作联动逻辑

G1 的三类 GC 流程并非孤立执行,而是根据堆内存使用情况动态联动,形成完整的整堆 GC 生命周期,典型执行流程如下:

  1. 程序启动→新对象分配到Eden Region →Eden Region 满→触发 Young GC(STW,复制回收新生代,清空 Eden);
  2. 多次 Young GC 后→存活对象在 Survivor Region 间复制,年龄达阈值后晋升到 Old Region→老年代 Region 使用率逐步升高;
  3. 老年代 Region 使用率达阈值(默认 45%)→触发 Mixed GC(初始标记→并发标记→最终标记→筛选回收),同时回收新生代 + 部分老年代;
  4. 若一次 Mixed GC 后老年代使用率仍高→连续触发多次 Mixed GC,逐步回收老年代垃圾,直到使用率降至阈值以下;
  5. 程序继续运行,重复步骤 1-4,形成循环;
  6. 异常场景下(如堆内存不足、大对象分配失败)→触发 Full GC(兜底,长时间 STW)。

四、G1 的核心优化机制(对比 CMS,全维度升级)

G1 的工作原理中融入了多项核心优化,彻底解决了 CMS 的所有缺陷,也是其成为 JDK9 + 默认收集器的关键,核心优化点如下:

优化点 G1 实现方式 CMS 缺陷
无内存碎片 全程采用复制算法,存活对象集中存储在连续 Region 标记 - 清除算法,产生大量内存碎片,导致大对象分配失败
停顿时间可预测 筛选回收阶段按需选择 Region,严格控制 STW 时间 无整体停顿时间控制,STW 时间随堆内存增大而增加
无并发模式失败 Region 化管理,按需回收老年代,避免老年代内存被快速占满 并发阶段老年代内存不足,触发 Concurrent Mode Failure,切换为 Serial Old Full GC
整堆统一管理 自身实现新生代 + 老年代回收,无需搭配其他收集器 仅负责老年代,需搭配 ParNew 做新生代回收,逻辑复杂
跨代引用优化 SATB 机制 + 卡表,仅处理引用变动记录,避免全堆扫描 重新标记阶段全量扫描,开销随堆内存增大而增加
超大对象优化 单独的 Humongous Region 存储,连续分配,避免碎片化影响 无专门大对象区,大对象易因碎片无法分配

五、G1 核心配置参数

G1 的工作行为可通过 JVM 参数精准控制,核心参数均为 JDK8 + 可用,生产环境中优先使用默认值,仅在出现性能问题时针对性调参:

复制代码
# 核心开启参数
-XX:+UseG1GC  # 开启G1收集器(JDK9+默认,JDK8需手动开启)

# 停顿时间控制(核心调参项)
-XX:MaxGCPauseMillis=200  # 设置GC最大停顿时间,默认200ms,根据业务需求调整(如低延迟场景设为100ms)

# Region大小配置
-XX:G1HeapRegionSize=4M  # 指定Region大小(1M~32M,2的幂次),默认自适应,大内存场景可适当调大

# 老年代回收触发阈值
-XX:InitiatingHeapOccupancyPercent=45  # 老年代使用率达45%时触发Mixed GC,默认45%,堆内存不足时可适当调低

# 新生代占比控制
-XX:G1NewSizePercent=5  # 新生代Region最小占比,默认5%
-XX:G1MaxNewSizePercent=60  # 新生代Region最大占比,默认60%

# 禁用显式Full GC
-XX:+DisableExplicitGC  # 禁止通过System.gc()显式触发Full GC,默认关闭

# GC线程数配置
-XX:ParallelGCThreads=8  # STW阶段的并行GC线程数,默认等于CPU核心数
-XX:ConcGCThreads=4  # 并发阶段的GC线程数,默认是ParallelGCThreads的1/4

六、核心总结

G1 通过Region 化整堆管理 将堆划分为大小相等的内存块,基于垃圾优先策略 按垃圾比例排序 Region,通过三类分层 GC 流程 实现全堆回收:Young GC 高频短停顿回收新生代 ,Mixed GC(核心)通过 "并发标记 + 可控筛选回收" 同时回收新生代 + 部分老年代,保证停顿时间可预测 ,Full GC 仅作为异常兜底 ;全程采用复制算法 实现无内存碎片回收,结合SATB 机制 优化跨代引用,彻底解决了经典 GC 的缺陷,是 JDK8 + 生产环境大内存、低延迟场景的首选收集器。

核心记忆点

  1. G1 的核心是 **「Region 化 + 垃圾优先 + 可预测停顿」**;
  2. Mixed GC 是 G1 唯一回收老年代的流程,也是实现低延迟的关键;
  3. G1 全程复制算法,无内存碎片,是对比 CMS 最核心的优势;
  4. G1 的 STW 时间由-XX:MaxGCPauseMillis精准控制,适配绝大多数低延迟业务场景。
相关推荐
西瓜拿铁好喝3 小时前
开源和闭源 AI 办公工具,分别适合谁
java·前端·数据库
学长毕设3 小时前
基于SpringBoot的校园礼服租赁系统的设计与实现
java·spring boot·后端
lpfasd1233 小时前
推荐算法进化史
算法·机器学习·推荐算法
明天也要努力学习3 小时前
深入理解 JVM 垃圾回收(GC)
java·jvm
铁链鞭策大师3 小时前
jvm基础
jvm
Pniubi3 小时前
力扣543二叉树的直径(深度优先搜索法(递归))
算法·leetcode·职场和发展
golang学习记3 小时前
IDEA 断点调试技巧:拖拽
java·ide·intellij-idea
Sayai3 小时前
Flink 日志解析任务性能优化实战:正则/Grok 预编译、Guava 缓存权重陷阱与 ES 写入隔离
java·大数据·性能优化·flink·实时计算
计算机毕设定制辅导-无忧学长3 小时前
《基于物品协同过滤的闲置书换购微信小程序设计开发》
java·vue.js·spring boot·微信小程序·uniapp·闲置书换购微信小程序·物品协同过滤算法
Best_Liu~3 小时前
SpringBoot全局日期格式化
java·spring boot·后端