Shenandoah通过硬件级CAS原子更新对象头8字节转发指针(初始指向自身),确保迁移状态一致;读屏障据此实时跳转,使旧引用兜底有效,无需同步所有引用点。

Shenandoah 对象移动过程中,指针的原子更新是整个并发迁移机制可靠运行的底层基石。它不依赖全局停顿或锁协调,而是靠硬件级原子指令直接保障单个对象转发状态的一致性。
转发指针的结构与初始状态
每个对象头前固定预留 8 字节空间,作为转发指针(Forwarding Pointer),不是 Brooks Pointer 的间接容器设计,而是直接嵌入的可原子写入字段:
- 初始值指向对象自身地址(self-forwarded),表示尚未被疏散
- 该字段不参与对象字段布局,JIT 编译器能识别并优化访问路径
- 字段位置固定、大小确定,便于读屏障快速定位和检查
CAS 更新确保无竞态切换
当 GC 线程完成对象复制后,立即对该转发指针执行一次 CAS(Compare-And-Swap)操作:
- 仅当当前值仍为原地址时,才将其原子更新为新副本地址
- 若 CAS 失败(说明其他线程已抢先更新),当前线程直接使用新地址,不再重复复制
- 整个过程在纳秒级完成,避免了锁、信号量或内存屏障的额外开销
读屏障如何依赖这个原子状态
每次通过引用访问对象字段前,JVM 插入轻量读屏障,其行为完全取决于转发指针的当前值:
- 若指针已更新为新地址,屏障直接跳转并加载目标字段
- 若仍为 self-forwarded,则按原地址访问——此时对象未移动,数据有效
- 不存在“部分更新”或“中间值”,因为 CAS 是全有或全无的原子操作
为什么不需要同步所有引用点
原子更新转发指针本身,就解耦了“对象迁移完成”和“引用是否修正”两个问题:
- 栈中局部变量、寄存器里的旧地址无需立即失效,访问时由读屏障兜底重定向
- 堆内字段引用可延迟更新(Concurrent Update References 阶段),属于性能优化而非语义必需
- GC Roots 引用(如静态变量、JNI 全局引用)只在极短 STW 阶段统一处理,数量有限

















