从内存布局到底层算法 · 分镜式专业拆解
💡 核心定位差异
G1:主打「可预测停顿」的分代回收器,在吞吐量和停顿之间做平衡,是Java 11+默认GC,适合大多数业务场景。
ZGC:主打「极低停顿」的并发回收器,亚毫秒级暂停,支持TB级堆,适合大内存、低延迟要求的核心服务,Java 21引入分代后吞吐量大幅提升。
Region 化分代设计
Region 化 + Java21 分代
标记GC Roots直接引用的对象,停顿时间很短,和年轻代大小相关
遍历对象图标记存活对象,和应用线程并发运行;用SATB快照保证一致性
处理SATB剩余引用,完成最终标记;停顿时间较短,和堆大小无关
根据停顿预测模型选择回收价值最高的Region,复制存活对象;停顿时间主要在这里
标记GC Roots直接引用,停顿极短(<1ms),只和GC Roots数量相关
并发遍历标记,同时完成对象移动整理;读屏障保证并发安全,几乎所有工作都在这一步
完成最终标记,处理根重定位;停顿依然亚毫秒级,和堆大小完全无关
💡 核心差异
ZGC的对象复制整理也是并发的,G1的筛选回收是全停顿的;这是两者停顿时间差距的根本来源。
1. SATB 快照算法
并发标记开始时拍下对象图快照,通过写屏障记录引用变化,保证标记期间的引用修改不影响结果准确性。
2. Remembered Set 记忆集
每个Region维护一份引用记录,记录其他Region指向本Region的引用;避免回收时扫描全堆,代价是额外内存占用(约5%)。
3. 停顿预测模型
根据历史回收数据计算每个Region的回收成本,在满足-XX:MaxGCPauseMillis目标的前提下,选择回收价值最大的Region组合。
4. 混合回收模式
每次回收同时回收年轻代和部分老年代Region,兼顾吞吐量和停顿时间,增量式回收避免全堆GC。
1. 染色指针 Colored Pointers
利用对象指针的高位4位存储对象元信息(标记位、重定位位等),直接从指针就能知道对象状态,不需要额外的标记位图。 这是ZGC并发整理的关键
2. 读屏障 Load Barrier
读取对象指针时触发屏障,检查指针染色位;如果对象已被移动则自动修正指针,对应用层完全透明,保证并发移动的正确性。
3. 并发整理 Compaction
回收过程中并发完成对象复制和内存整理,彻底解决内存碎片问题;这是G1做不到的,G1整理需要全停顿。
4. 分代ZGC(Java21)
引入年轻代分代回收,频繁回收年轻对象,大幅降低并发回收压力,吞吐量提升25%以上,同时保持亚毫秒停顿。
| 对比维度 | G1 GC | ZGC |
|---|---|---|
| 典型停顿时间 | 10ms ~ 200ms(随堆增大而变长) | < 1ms(亚毫秒级,与堆大小无关) |
| 停顿决定因素 | 堆大小、存活对象数量、Region数量 | GC Roots 数量(通常几千个) |
| 最大支持堆大小 | ~ 64GB(再大停顿不可控) | ~ 16TB(官方标称) |
| 吞吐量 | 高(约90%+),Java 21前占优 | 中高(约85%+),分代ZGC追平G1 |
| 内存碎片 | 少量碎片,Region复制缓解 | 几乎无碎片,并发完整整理 |
| 分代回收 | 原生完整分代 | Java 21 正式引入分代 |
| 额外内存开销 | 约5%(Remembered Set) | 约10~15%(染色指针、标记数据) |
| CPU 占用 | 中等 | 较高(并发线程多) |
| 默认版本 | Java 9 ~ Java 21 默认GC | 需手动开启,Java 21 生产可用 |
👉 选 G1 的场景
👉 选 ZGC 的场景
💡 一句话决策
8G以下用G1省心;16G以上追求低延迟上ZGC;Java21+大堆直接上分代ZGC。
G1 关键参数
-XX:MaxGCPauseMillis=200 目标停顿时间-XX:G1HeapRegionSize 设置Region大小-XX:G1NewSizePercent 年轻代最小比例-XX:G1MaxNewSizePercent 年轻代最大比例-XX:InitiatingHeapOccupancyPercent 触发并发标记阈值ZGC 关键参数
-XX:+UseZGC 启用ZGC-XX:+ZGenerational 开启分代ZGC(Java21+)-XX:ConcGCThreads 并发GC线程数-XX:ZCollectionInterval 最小回收间隔-XX:+UseNUMA 开启NUMA优化误区1:ZGC 是零停顿 GC
错。ZGC 依然有 STW 阶段(标记开始/结束),只是停顿时间极短(<1ms),且不随堆大小增长,不是完全没有停顿。
误区2:ZGC 没有分代
过时了。Java 21 正式引入分代 ZGC,年轻代回收效率大幅提升,吞吐量已经追平 G1。
误区3:ZGC 一定比 G1 好
错。小堆(8G以下)场景下 G1 表现更均衡,ZGC 有额外内存和CPU开销,优势发挥不出来。
误区4:G1 停顿时间是固定的
错。MaxGCPauseMillis 是目标值不是保证值,堆过大、存活对象过多时停顿会超出目标。
G1 通用配置(8G堆)
java -Xms8g -Xmx8g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:InitiatingHeapOccupancyPercent=45 \
-XX:+ParallelRefProcEnabled \
-XX:+HeapDumpOnOutOfMemoryError \
-jar app.jar
分代ZGC配置(32G堆 Java21)
java -Xms32g -Xmx32g \
-XX:+UseZGC \
-XX:+ZGenerational \
-XX:+UseNUMA \
-XX:ConcGCThreads=4 \
-XX:+HeapDumpOnOutOfMemoryError \
-jar app.jar
G1 GC vs ZGC 深度对比漫画图鉴 | 基于 JDK 21 最新规范