Shenandoah实现超低停顿的关键是“不等”而非“少做”,即通过Brooks Pointer(对象头转发指针)和读屏障在应用运行时并发完成引用重定向,避免STW更新所有引用;初始与最终标记仅需约1ms,其余阶段全程并发。

Shenandoah 实现超低停顿,关键不在“少做”,而在“不等”——它把原本必须暂停应用线程才能完成的内存同步操作,全部挪到应用运行过程中并发执行。核心是用Brooks Pointer和读屏障(Load Barrier)替代传统写屏障,在对象访问路径上轻量拦截并动态修正引用,从而彻底压缩 STW 阶段。
Brooks Pointer:每个对象头上加一层转发指针
Shenandoah 不直接修改对象头或全局元数据,而是在每个对象起始位置前插入一个额外的指针字段(Brooks Pointer),默认指向对象自身。当该对象需要被转移(Relocate)时,GC 线程只更新这个指针为目标地址;后续任意线程读取该对象时,读屏障会自动检查并重定向到新位置,整个过程对应用透明。
- 避免了传统复制算法中“更新所有引用”的全局扫描开销
- 无需在 Evacuation 阶段 STW 去修正堆内、栈中、寄存器里的全部引用
- 每个对象的重定向是惰性、按需触发的,压力分散而非集中爆发
读屏障:在每次对象加载时做一次轻量判断
JVM 在字节码解释器、C1/C2 JIT 编译器中为所有对象引用加载指令(如 aload, getfield)注入读屏障逻辑。该屏障仅做两件事:
- 检查目标对象的 Brooks Pointer 是否已指向新地址
- 若已重定向,直接返回新地址;否则触发一次快速重定位并更新指针
这个检查平均耗时约 5–10 纳秒,远低于一次缓存未命中代价,且完全不阻塞应用线程。
并发重映射(Concurrent Remap):延迟处理,分批清理
重定位完成后,旧地址空间仍可能被部分未触发读屏障的引用持有。Shenandoah 不强求立刻修复所有旧引用,而是启动后台并发线程,逐步扫描根集(栈、寄存器、JNI 引用等)和已知活跃区域,批量更新残留引用。这一阶段全程并发,无 STW。
- 初始标记和最终标记两个 STW 阶段仅用于快照根集合,通常控制在 1ms 内
- 标记、转移、重映射三大阶段全部与用户线程并发执行
- 即使突发大量分配,也只影响增量回收节奏,不导致停顿跳升
与 ZGC 的同步策略对比
ZGC 用染色指针(Colored Pointers)将元信息编码进引用本身,靠地址高位标识状态,依赖硬件支持的多重映射;Shenandoah 则选择软件层更可控的 Brooks Pointer + 读屏障组合,对 CPU 架构无特殊要求,兼容性更好,尤其在容器受限地址空间或 ASLR 开启环境下更稳定。

















