Shenandoah 并发处理机制核心是转发指针+读屏障+原子操作:对象头嵌入8字节原子字段,GC线程CAS更新为新地址,读屏障在每次字段访问前检查并自动跳转,确保用户线程不停顿、访问始终命中最新副本。

Shenandoah 的并发处理机制核心在于不依赖全局停顿来同步读写,而是靠对象级的转发指针 + 读屏障 + 原子操作,在用户线程持续运行的前提下,安全完成对象移动与引用访问。它解决的不是“要不要停”,而是“怎么不停也能对”。
转发指针(Brooks Pointer)是读写一致性的基础
每个对象头额外携带一个指针字段,默认指向自身;当 GC 线程决定移动该对象时:
- 先在目标 Region 中复制一份新副本
- 再原子地将原对象头中的转发指针更新为新地址
- 此后所有对该对象的访问,都通过该指针间接跳转
这个指针更新是原子的(如使用 CAS),避免多线程竞争导致旧/新地址混用。
读屏障拦截每次对象读取,实现透明重定向
JVM 在字节码层面或 JIT 编译时,在对象字段读取指令前插入读屏障逻辑:
- 检查被访问对象头的转发指针是否已设置
- 若已设置,直接返回新地址上的值,用户线程无感知
- 若未设置,按原地址读取(说明尚未被回收选中或正在移动中)
- 写操作同样经过读屏障,确保不会向已失效的旧内存位置写入数据
这使得用户线程无需修改代码、也不知对象已被移动,访问始终落在有效副本上。
写操作的安全控制:禁止写入旧副本
Shenandoah 不允许用户线程直接写入原对象内存区域(除非转发指针仍指向自己):
- 一旦转发指针被更新,后续任何写入都会被读屏障引导至新地址
- 原内存区域仅保留只读语义,直到所有引用完成重定向且确认无活跃访问后,才由 GC 线程回收
- 这从机制上杜绝了“一边写旧地址、一边清理旧地址”导致的数据错乱
根引用更新只需极短 STW,不拖累整体并发性
真正需要暂停的,只是少量 GC Roots(如 Java 栈帧、静态变量、JNI 引用等):
- 它们数量有限,更新耗时通常在亚毫秒级
- 不涉及堆内海量引用的批量修正,因此 STW 时间与堆大小无关
- 用户线程其余时间完全自由运行,读写逻辑不受干扰
这套机制把一致性保障从“全堆同步”降维到“单对象+单访问”,让并发整理成为可能。

















