ZGC能稳定实现亚毫秒级停顿,根本原因在于有色指针、读屏障和多映射内存三重底层机制创新:指针自带状态免同步更新,读屏障单次自愈无锁修正,多映射内存支持并发压缩。

读屏障:ZGC 的核心延迟控制机制
ZGC 通过在每次对象引用加载(load reference)时插入一段轻量级的 读屏障(Load Barrier) 代码,实现在不暂停应用线程的前提下完成并发标记与重定位。它不是在每次内存访问都做完整检查,而是仅当加载一个可能已被重定位的对象指针时才触发屏障逻辑。
读屏障的核心作用是:在应用线程读取对象引用时,自动判断该指针是否指向旧地址;如果是,就透明地将其更新为新地址(即“转发”),并返回新地址给应用线程——整个过程对 Java 代码完全透明,且耗时极短(通常几十纳秒)。这避免了传统 GC 中“Stop-The-World”式遍历对象图或修正所有引用的开销。
染色指针:用指针元数据替代额外标记空间
ZGC 将对象标记信息(如是否已标记、是否正在重定位)直接编码进 64 位指针的高位中,称为 染色指针(Colored Pointers)。在 Linux/x64 上,ZGC 实际只使用 42 位地址空间(支持 4TB 堆),剩余高位用于存储颜色位(Marked0/Marked1/Remapped/Unused)。
这种设计带来两个关键优势:
立即学习“Java免费学习笔记(深入)”;
- 无需单独维护 bitmap 或 mark word 来记录对象状态,节省内存且避免缓存污染
- 读屏障能直接从指针本身快速解码对象当前状态,比如看到
Marked0位就知该对象已标记但未重定位,看到Remapped位则说明已是最新地址,可直接使用
并发标记与重定位如何协同工作
ZGC 将 GC 周期分为三个主要并发阶段:初始标记(STW,极短)、并发标记、并发重定位。读屏障和染色指针在这两个并发阶段中紧密配合:
-
并发标记阶段:GC 线程遍历对象图,将存活对象指针的染色位设为
Marked0;同时,应用线程通过读屏障访问对象时,若发现指针未标记,会协助完成标记(“自愈式标记”),保证不漏标 -
并发重定位阶段:GC 线程将存活对象复制到新地址,并将原指针染色为
Remapped;应用线程一旦通过读屏障读到旧地址(如Marked0),就触发重定位:原子地将对象复制到新位置、更新 forwarding pointer、再把当前指针改为新地址并染色为Remapped
由于所有引用修正都在读取时按需发生,ZGC 完全避免了“记忆集(Remember Set)”或“写屏障导致的写放大”问题,也无需在 STW 阶段扫描整个堆或卡表。
为什么能做到亚毫秒级停顿
ZGC 的 STW 暂停仅发生在初始标记和最终重映射两个极短环节,且都只涉及根集合(线程栈、寄存器、全局 JNI 句柄等),不扫描堆内存:
- 初始标记:只扫描 GC Roots 直接引用的对象,时间与活跃线程数成正比,通常
- 最终重映射:只修正那些在并发重定位阶段仍未被读屏障触及的根中残留旧指针,实际极少,一般
其余所有繁重工作——标记、移动、修正引用——全部由读屏障在应用线程运行时“摊平”执行,真正实现 GC 工作与应用执行的细粒度交织,从而稳定保持停顿时间在 10ms 以内,甚至低于 1ms。


















