09.1 - ZGC 原理
定位: 亚毫秒级停顿的全并发 GC——彩色指针 + 负载屏障,让 GC 不再是延迟瓶颈 面试高频度: ⭐⭐⭐⭐
一、这是什么?为什么需要它?
**垃圾收集器详解(Serial到ZGC)** 介绍了 GC 收集器的演进。在 ZGC 之前,已有收集器的 STW 停顿存在一个硬约束:
- CMS: STW 停顿随堆大小增长。32GB 堆 → CMS 并发标记阶段约 50-100ms
- G1: 可预测停顿目标,但大堆(>64GB)下 STW 仍可能到 10-50ms
核心矛盾:现代应用需要低延迟(<10ms P99),传统 GC 做不到。
ZGC(JDK 11 实验 → JDK 15 正式 → JDK 21 分代)的目标:无论堆多大(8MB 到 16TB),STW 停顿 < 1ms(实测通常在 0.2-0.5ms)。
二、原理拆解
2.1 为什么传统 GC 停顿长?
垃圾收集需要做三件事:标记(Mark)→ 重定位(Relocate)→ 重映射(Remap)。前两件事最难并发化:
- 标记阶段要遍历整个对象图 → 如果应用线程同时修改引用(三色标记的"黑→白"问题),必须用 STW 或复杂屏障解决
- 重定位要移动对象 → 移动一个对象后,所有引用它的指针都要更新。如果应用线程正在用旧地址访问,就会崩溃
G1 的重定位是 STW 的——暂停所有线程移动对象 + 更新引用。堆越大、对象越多,停顿越长。
2.2 ZGC 的核心突破
ZGC 用两项核心技术实现了全并发:
彩色指针(Colored Pointers)
传统 64 位指针:
┌──────────────────────────────────────────────────────────────────────────┐
│ 0000 0000 0000 0000 00┌────────────────── 地址位 (48bit) ──────────────┤
└──────────────────────────────────────────────────────────────────────────┘
ZGC 彩色指针 (64bit):
┌──────┬──────┬──────┬──────┬──────────────────────────────────────────────┐
│ │ │ │ │ │
│ M1 │ M0 │ Rmtd │ Fin │ 地址位 (42bit → 4TB 可寻址) │
│(1bit)│(1bit)│(1bit)│(1bit)│ │
└──────┴──────┴──────┴──────┴──────────────────────────────────────────────┘
M1 = Marked 1 (奇数 GC 周期已标记)
M0 = Marked 0 (偶数 GC 周期已标记)
Rmtd = Remapped (指针已更新为新地址)
Fin = Finalizable (只被 Finalizer 可达)为什么把这个信息放进指针?
传统 GC 需要额外 metadata(如 G1 的 RSet、记忆集)来记录对象状态。ZGC 把"对象当前处于哪个 GC 阶段"编码到指针本身中——指针就是 metadata。
这意味着:
- 查状态 = 一次位运算(不是 hash 查找)。Load barrier 开销极小
- 不同 GC 周期用不同标记位(M0/M1 交替)→ 不用清空标记
- 重映射状态内置 → 并发重定位安全
负载屏障(Load Barrier)
// 每个对象字段访问实际变成了:
Object x = obj.field;
// JVM 内部实际: x = load_barrier(obj.field);
Object load_barrier(Object ref) {
if (ref.color == NEEDS_FIX) { // 快速路径:位运算检查
ref = fix_up(ref); // 慢速路径:重映射至新地址
}
return ref;
}原理:每次 obj.field 读取时,检查指针的颜色位。如果颜色显示"这个指针需要处理"(比如对象已经被移到新地址),则进入慢速路径更新指针。否则原样返回。
这不是 STW——应用线程继续运行,每个 load 只多一次位运算检查。命中慢速路径时,fix-up 也只更新这一个指针,不会暂停。
全并发架构
ZGC 的并发阶段:
重映射(懒) ← 随下次GC的
┌──────────┐ 负载屏障自动完成
│ STW: │
│ Root扫描 │
│ (<0.1ms) │
└────┬─────┘
│
┌────▼─────┐ ┌──────────────┐ ┌─────────────────┐
│ 并发标记 │ │ STW: │ │ 并发重定位 │
│ (所有线程) │ │ 标记结束+准备 │ │ (所有线程运行中) │
│ 三色标记 │───→│ 重定位 │───→│ 移动对象 │
│ 彩色指针 │ │ (<0.1ms) │ │ 更新转发表 │
│ 不会漏标 │ └──────────────┘ │ 负载屏障修正 │
└───────────┘ └─────────────────┘每个周期实际只有 2 个 STW 暂停,各 < 0.1ms:根扫描 + GC 结束准备。标记和重定位都是并发的。
2.3 分代 ZGC(JDK 21+)
为什么需要分代?
- 绝大多数对象(80-95%)在 Young GC 中就死亡了
- 不分代的 ZGC 每次都要标记整个堆 → 对短期对象扫描浪费
- 分代后:Young GC 只扫描年轻代 + Remembered Set → 10-20% 吞吐量提升
分代 ZGC 的堆:
┌─────────────────────────────────────────────────────────────────────┐
│ ZGC Heap │
│ ┌──────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ Young Region │ │ Old Region │ │
│ │ (频繁 GC) │ │ (少量 GC) │ │
│ │ 快速标记+重定位 │ │ 并发标记+重定位 │ │
│ └──────────────────┘ └──────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Remembered Set: Young 到 Old 的跨代引用 (避免扫描整个 Old) │ │
│ └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘三、图解全景
ZGC vs G1 停顿对比 (64GB 堆):
停顿时间 (ms):
100 │ G1
50 │ ██
20 │ G1 ██
10 │ ██ ██
5 │ G1 ██
1 │ G1 ██ ZGC
0.5│ ██ ZGC ZGC ZGC
0.1│ ZGC
└─────────────────────────────────────────────
Root扫描 标记 重定位 汇总四、面试视角
| 面试题 | 核心回答 |
|---|---|
| ZGC 的彩色指针是什么? | 64 位指针中用 4 位存储 GC 状态(M1/M0/Rmtd/Fin),指针本身即 metadata,负载屏障通过位运算检查 |
| ZGC 为什么能做到亚毫秒停顿? | 只有根扫描和阶段收尾是 STW(<0.1ms),标记和重定位全是并发的。负载屏障让应用线程在重定位时自己修正指针 |
| ZGC 和 G1 的区别? | G1 有 STW 重定位(堆越大停顿越长),依赖 RSet 和 SATB;ZGC 全并发,彩色指针 + 负载屏障,适合大堆和低延迟场景。ZGC 内存开销稍高(存储转发表) |
| 分代 ZGC 的优势? | 不分代每次要标记整个堆。分代后 Young GC 只扫描年轻代 + Remembered Set,吞吐量提升 10-20%,降低年轻对象回收延迟 |
| ZGC 有什么缺点? | 内存占用稍高(转发表)、对 CPU 有额外负载(所有 load 经过 barrier)、大堆场景优势更明显、小于 4GB 的堆不如 G1 |
追问预判
问: ZGC 的彩色指针为什么用 42 位地址?
- 答: 64 位中 4 位用作颜色、剩余若干位保留,42 位可寻址 4TB 堆。地址位是 4×4TB 的倍数地址映射(多重映射技术),不是纯数学计算
问: ZGC 的负载屏障和 G1 的写前屏障有什么区别?
- 答: ZGC 是读屏障(load barrier),G1 是写屏障(SATB + 日志记录)。ZGC 用读屏障在并发重定位时修正引用,G1 用写屏障维持 SATB 快照。ZGC barrier 开销更低(读路径更常见)
问: ZGC 适合多大堆?
- 答: 官方范围 8MB-16TB。实测建议 >4GB 有明显优势。小于 4GB 的堆,G1 因 barrier 开销更低而更合适
📚 相关链接
- **垃圾收集器详解(Serial到ZGC)** — GC 收集器全景
- **GC基本算法(标记清除与复制与标记整理)** — 三色标记算法基础
- **虚拟线程原理** — 另一个"全并发"前沿特性,了解 ZGC 后对比虚拟线程的并发策略
- ← 返回 **前沿索引**