标记-清除算法必须stw以保证对象图一致性,防止漏标、错标及误回收;stw发生在标记开始前和清除开始前,确保堆快照瞬时一致且标记结果不被干扰。

标记-清除算法执行时必须暂停所有用户线程,也就是触发 Stop-The-World(STW),核心原因只有一个:保证对象图的一致性,避免标记结果错漏。
标记阶段从 GC Roots 出发遍历可达对象,若不暂停业务线程,正在运行的代码可能随时修改引用关系——比如新建对象、改变字段指向、断开引用等。这种并发修改会导致两种严重错误:
- 漏标:一个本该存活的对象,在标记开始后被新引用指向,但因未被重新扫描而被误判为垃圾;
- 错标/误回收:一个刚被标记为存活的对象,后续又被业务线程解除所有引用,但因已标记而逃过清除,造成内存泄漏;更危险的是,若在“标记完成→清除开始”之间创建新对象,它没被标记,却会被当作垃圾清除——程序直接崩溃。
所以 JVM 在标记-清除的两个关键节点强制 STW:
- 标记开始前:暂停所有用户线程,获取一个瞬时一致的堆快照;
- 清除开始前(有时也合并到标记结束时):确保标记结果不再被业务逻辑干扰,再统一清理未标记对象。
这个暂停不是全程停顿——标记和清除本身由 GC 线程串行执行,但业务线程全程冻结,直到整个标记-清除流程完成才恢复。
常见实现细节:
- 初始标记(如 CMS 的 initial-mark)和重新标记(remark)都需 STW,前者抓根集合,后者修正并发期间变动;
- G1 在初始标记和最终标记阶段同样触发 STW,尽管大部分标记工作是并发的;
- STW 时间取决于堆大小、GC Roots 数量、对象图复杂度,但与是否并发标记无关——只要涉及“全局一致性判定”,就绕不开短暂停顿。
本质上,STW 不是设计缺陷,而是安全代价:宁可短暂卡顿,也不能让对象生死判断出错。











