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精准控制,适配绝大多数低延迟业务场景。
相关推荐
Max_uuc2 小时前
【C++ 硬核】打破嵌入式 STL 禁忌:利用 std::pmr 在“栈”上运行 std::vector
开发语言·jvm·c++
吃杠碰小鸡2 小时前
高中数学-数列-导数证明
前端·数学·算法
故事不长丨2 小时前
C#线程同步:lock、Monitor、Mutex原理+用法+实战全解析
开发语言·算法·c#
long3162 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
近津薪荼2 小时前
dfs专题4——二叉树的深搜(验证二叉搜索树)
c++·学习·算法·深度优先
熊文豪2 小时前
探索CANN ops-nn:高性能哈希算子技术解读
算法·哈希算法·cann
Serene_Dream2 小时前
JVM 并发 GC - 三色标记
jvm·面试
熊猫_豆豆2 小时前
YOLOP车道检测
人工智能·python·算法
rannn_1112 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习