stw无法完全避免,根本原因是根对象扫描、对象移动和安全点机制等关键操作必须保证内存状态绝对一致,而只有暂停所有应用线程才能可靠达成;并发gc仅缩短停顿时间,却无法消除其必要性。

GC中的STW无法完全避免,根本原因在于某些关键操作必须保证内存状态的绝对一致性——而这种一致性,只有在所有应用线程暂停时才能可靠达成。
根对象扫描必须原子完成
GC的第一步是从GC Roots(如Java虚拟机栈、本地方法栈、静态变量、常量池等)出发标记存活对象。这些根集合本身是动态变化的:线程可能正在压栈、出栈,或修改局部变量引用。如果不停止线程,根集会“边扫边变”,导致漏标——本该存活的对象被当作垃圾回收,引发严重逻辑错误(如对象突然为null、程序崩溃)。因此,初始和最终的根扫描必须在STW下完成,且无法并发化。
对象移动需要地址一致性保障
压缩式GC(如Parallel GC、ZGC的重定位阶段)需将存活对象复制或移动到新内存位置,并更新所有指向它的引用。这个过程要求: • 对象旧地址不再被任何线程访问; • 所有引用字段必须同步更新为新地址。 若应用线程并发读写正在移动的对象,轻则读到脏数据,重则访问已失效地址(野指针)。STW是唯一能确保“移动-更新”原子完成的安全机制。
安全点机制天然依赖停顿
JVM不会在任意指令处中断线程,而只允许在线程到达“安全点”(如方法返回、循环边界、对象分配点)时暂停。这本身就需要线程主动轮询或响应信号,等待其进入可中断状态。即使现代GC(如ZGC、Shenandoah)将STW压缩到亚毫秒级,仍需至少两次短暂停顿:一次获取初始根集,一次校验并发标记结果。这不是实现不够好,而是语义正确性的硬性约束。
并发算法仍需协调临界动作
像Go的三色标记或Java的CMS/G1,虽将大部分标记/清除工作并发执行,但必须插入读屏障、写屏障来捕获运行时引用变更。这些屏障本身带来开销,且无法覆盖所有场景(例如栈上临时引用、JNI本地代码)。最终仍需STW做“兜底校验”,修正并发过程中可能产生的标记偏差。换句话说:并发降低停顿时长,却不消除停顿必要性。
本质上,STW不是技术缺陷,而是内存安全性与程序正确性之间的必要妥协。再先进的GC,只要基于追踪式回收、支持对象移动、依赖可达性分析,就绕不开这几个不可并发的原子环节。










