shenandoah通过并发疏散、brooks指针转发和增量式区域回收实现亚十毫秒级停顿:它用转发指针支持读写隔离,将疏散与引用更新全移至并发阶段,仅需极短stw标记,且region回收可中断、自适应。

Shenandoah 是 Java 12 引入、Java 15 起默认可用的低延迟垃圾回收器,核心目标是大幅缩短 GC 停顿时间(STW),尤其适用于对响应时间敏感的应用(如金融交易、实时游戏、API 网关)。它通过“并发疏散”实现这一点——即在应用线程仍在运行时,就完成对象的复制与重定位。理解其运作机制,关键在于把握“读屏障 + 并发转移 + Brooks 指针”这一技术组合。
启用 Shenandoah 并确认生效
使用 Shenandoah 需显式启用,并确保 JDK 版本支持(推荐 JDK 17+ 或 JDK 21 LTS):
- 启动参数:-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC(JDK 12–14);JDK 15+ 可简化为 -XX:+UseShenandoahGC
- 验证是否启用成功:添加 -Xlog:gc*:gc.log:time,tags,启动后日志中出现 Shenandoah 字样及 Concurrent evacuation 等阶段标记
- 可选调优:用 -XX:ShenandoahGCHeuristics=aggressive 加速回收节奏,或 -XX:ShenandoahUncommitDelay=1000 控制内存释放延迟
读屏障(Load Barrier)是并发安全的核心
Shenandoah 不依赖 Stop-The-World 来冻结对象图,而是靠在每次对象引用读取时插入轻量级检查逻辑——这就是读屏障。它不拦截写操作,只在 读取对象字段或数组元素前 触发:
- 若该对象已被标记为“正在转移”,读屏障会自动将其转发到新地址(并可能触发转移本身)
- 转发过程是原子的,且仅影响当前读取路径,不影响其他线程继续运行
- 开销极小(现代 CPU 上约 1–2 条额外指令),远低于传统 STW 的全局暂停成本
并发疏散:对象复制与指针更新同步进行
疏散(Evacuation)指将存活对象从原内存区域复制到新区域。Shenandoah 将此过程拆解为多个细粒度任务,并由 GC 线程与应用线程协作完成:
- GC 线程负责扫描堆、识别待疏散区域、分配新空间、执行对象复制
- 应用线程在访问对象时,若发现其已标记为“待转移”,可通过读屏障触发即时转移(lazy evacuation),或直接读取已转移后的转发地址
- 所有对象头都携带一个 Brooks 指针(指向自身或新位置),作为转发入口;转移完成后,原位置的 Brooks 指针被更新为新地址,后续读取直接跳转
三阶段回收周期:初始标记 → 并发转移 → 最终标记/清理
Shenandoah 的完整 GC 周期包含多个并发阶段,其中仅两个极短的 STW 阶段用于快照一致性:
- 初始标记(Initial Mark):极短 STW,标记根对象(如栈帧、静态变量),耗时通常
- 并发标记(Concurrent Mark):与应用并发运行,遍历对象图并标记存活对象
- 并发转移(Concurrent Evacuation):核心低延迟阶段,边标记边复制,读屏障保障访问正确性
- 最终标记(Final Mark):短暂 STW,处理并发期间遗漏的引用更新(如卡表未覆盖的跨代引用)
- 并发清理(Concurrent Cleanup):回收无引用的旧区域,完全并发,无停顿
Shenandoah 的低延迟不是靠减少工作量,而是靠把原本必须串行执行的重活(如对象移动)拆解成可并行、可延迟、可按需触发的小任务,并用读屏障兜住语义一致性。它适合堆大(>4GB)、延迟敏感(P99 evacuation failure 和 update-refs 阶段耗时,它们可能暴露对象图突变频繁或内存碎片问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











