重标记阶段必须暂停用户线程,以确保对象引用关系快照一致性,修正并发标记期间因用户线程运行导致的漏标或误标;它聚焦于脏卡页、晋升对象及新关联gc roots的对象,通过stw实现精确终局检查,保障回收安全性,典型停顿仅几至十几毫秒。

重标记阶段必须暂停用户线程,是因为它要确保对象引用关系的快照一致性,从而修正并发标记期间因用户线程持续运行而产生的漏标或误标。
并发标记无法保证引用关系静止
在并发标记阶段,GC线程和用户线程同时运行。用户线程可能随时修改对象引用——比如断开某条引用链、新增跨代引用(如新生代对象持有了老年代对象)、或让原本不可达的对象重新被GC Roots关联。这些动态变更会导致标记结果不准确:部分本该存活的对象未被标记(漏标),或部分已死亡对象被错误保留(误标)。
重标记需完成一次精确的“终局检查”
该阶段不是从头扫描,而是聚焦于并发期间的变动点,例如:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 被写入的老年代卡页(Dirty Card),标识出可能产生新引用的区域
- 新生代中存活并晋升到老年代的对象(CMS需扫描新生代,确认其对老年代的引用)
- 并发标记过程中新创建且直接关联GC Roots的老年代对象
这些检查必须在所有用户线程统一暂停的状态下进行,否则一边扫描一边改引用,结果永远无法收敛。
不暂停就无法构建可靠回收视图
CMS的目标是安全清理——只回收真正不可达的对象。如果重标记不停顿,就无法获得一个稳定的、反映某一时刻真实可达性的对象图。哪怕只差一次引用更新,也可能导致存活对象被错误回收(严重故障),或浮动垃圾大量堆积(影响后续GC效率)。因此,哪怕耗时稍长,也必须STW来保障准确性。
实际停顿时间仍很短
由于重标记只处理增量变化,不遍历全堆,JDK 8起还默认启用多线程并行处理,典型耗时通常为几毫秒到十几毫秒。相比串行老年代GC动辄数百毫秒的STW,这种轻量级暂停正是CMS设计的关键权衡。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










