G1 GC(Garbage-First)是 Java HotSpot 虚拟机中的一款面向服务端、低延迟、高吞吐的垃圾回收器,自 JDK 7u4 引入,并在 JDK 9 成为默认垃圾回收器。G1 的设计目标是在可控的停顿时间内(Soft Real-Time)实现高吞吐量,适用于大内存(数十GB甚至更大)的应用场景。
1. G1 GC 的核心设计思想
G1 的核心思想是:
-
分块(Region-Based)
-
将堆划分为多个大小相等的 Region(默认约 2048 个,每个 Region 大小 1MB~32MB)。
-
每个 Region 可以是 Eden、Survivor、Old、Humongous(大对象) 中的一种。
-
动态调整 Region 的角色,避免传统分代 GC 的固定比例限制。
-
-
增量回收(Incremental Collection)
-
每次只回收部分 Region(而非整个堆),减少单次 GC 停顿时间。
-
通过 Remembered Sets(RSet) 和 Card Table 记录跨 Region 引用,避免全堆扫描。
-
-
可预测停顿模型(Soft Real-Time)
-
通过
-XX:MaxGCPauseMillis
(默认 200ms)设定目标停顿时间。 -
G1 会动态调整回收的 Region 数量,尽量满足停顿时间要求。
-
2. G1 GC 的内存布局
G1 的堆不再严格分为新生代和老年代,而是由多个 Region 组成:
Region 类型 | 说明 |
---|---|
Eden | 存放新分配的对象 |
Survivor | 存放 Minor GC 后存活的对象 |
Old | 存放长期存活的对象 |
Humongous | 存放超大对象(>50% Region 大小) |
Free | 空闲 Region,可用于分配新对象 |
特点:
-
动态调整:新生代和老代的大小不固定,由 G1 自动调整。
-
大对象优化:Humongous 对象直接进入老年代,避免多次拷贝。
3. G1 GC 的工作流程
G1 的垃圾回收分为 Young GC 和 Mixed GC 两种模式:
(1) Young GC(Minor GC)
触发条件:Eden 区满时触发。
过程:
-
根扫描(Root Scanning):多线程并行扫描 GC Roots(栈、静态变量等)。
-
标记存活对象:标记 Eden 和 Survivor 区的存活对象。
-
复制存活对象:
-
存活对象被复制到新的 Survivor 区(或晋升到 Old 区)。
-
清空 Eden 和旧的 Survivor 区。
-
-
更新 RSet:记录跨 Region 引用。
特点:
-
并行执行,减少 STW 时间。
-
动态调整新生代大小,适应不同负载。
(2) Mixed GC(Major GC)
触发条件:当老年代占用达到 -XX:InitiatingHeapOccupancyPercent
(默认 45%)时触发。
过程:
-
初始标记(Initial Mark,STW):标记 GC Roots 直接关联的对象(与 Young GC 同步执行)。
-
并发标记(Concurrent Mark):多线程并发标记所有存活对象。
-
最终标记(Remark,STW):修正并发标记期间变动的引用(使用 SATB 算法)。
-
清理阶段(Cleanup,STW):
-
统计各 Region 的存活对象比例,排序回收价值(Garbage-First)。
-
选择部分 Old Region 进行回收(Mixed GC)。
-
-
复制/整理(Evacuation):将存活对象复制到空闲 Region,并清理死亡对象。
特点:
-
增量回收:每次 Mixed GC 只回收部分 Old Region,避免长时间停顿。
-
可预测停顿:通过选择回收价值高的 Region(垃圾比例高),最大化回收效率。
4. G1 GC 的关键技术
(1) Remembered Set(RSet)
-
每个 Region 维护一个 RSet,记录其他 Region 对本 Region 的引用。
-
避免全堆扫描,提高回收效率。
(2) Card Table
-
将堆划分为 512B 的 Card,记录脏 Card(被修改的引用)。
-
用于辅助 RSet 更新。
(3) SATB(Snapshot-At-The-Beginning)
-
在并发标记阶段,G1 使用 SATB 算法记录标记开始时的对象图快照。
-
确保并发修改不会影响标记准确性。
5. G1 GC 核心参数
参数 | 作用 | 默认值 |
---|---|---|
-XX:+UseG1GC | 启用 G1 GC | false (JDK9+ 默认 true ) |
-XX:MaxGCPauseMillis | 目标最大停顿时间 | 200 (ms) |
-XX:InitiatingHeapOccupancyPercent (IHOP) | 触发 Mixed GC 的老年代占用阈值 | 45 (%) |
-XX:G1HeapRegionSize | 设置 Region 大小 | 自动计算(1MB~32MB) |
-XX:ParallelGCThreads | 并行 GC 线程数 | CPU 核心数 |
-XX:ConcGCThreads | 并发标记线程数 | ParallelGCThreads / 4 |
6. G1 GC 的优缺点
✅ 优点
-
可控停顿时间:适合低延迟应用(如金融交易、实时系统)。
-
大堆友好:适合数十 GB 甚至更大的堆内存。
-
内存整理:通过复制算法减少碎片。
-
自适应调整:动态调整新生代/老年代比例。
❌ 缺点
-
内存占用较高:RSet 和 Card Table 需要额外空间。
-
并发阶段 CPU 开销:并发标记会占用应用线程资源。
-
Full GC 仍可能发生(如晋升失败或并发模式失败时)。
7. G1 GC 适用场景
-
堆内存较大(6GB+) 的应用。
-
要求低延迟(<200ms) 的服务(如 Web 服务、微服务)。
-
替代 CMS,避免内存碎片问题。
8. G1 vs Parallel GC vs CMS
回收器 | 算法 | 停顿时间 | 适用场景 |
---|---|---|---|
Parallel GC | 分代+并行 STW | 高吞吐,长停顿 | 计算密集型 |
CMS | 并发标记-清除 | 低停顿,高碎片 | 中小堆,低延迟 |
G1 | 分区+标记整理 | 可控停顿,低碎片 | 大堆,平衡吞吐/延迟 |
ZGC | 全并发+染色指针 | 超低停顿(<10ms) | 超大堆,极致低延迟 |
总结
-
G1 GC 采用 Region 分区模型,支持增量回收和可预测停顿。
-
通过 Young GC + Mixed GC 组合,平衡吞吐和延迟。
-
适合大内存、低延迟场景,是 CMS 的替代方案。
-
在 JDK 9+ 中已成为默认 GC,适用于现代 Java 应用。