为什么 GC 需要在某些标记短语期间停止 mutator 线程?
Why the GC need to stop the mutator threads during some marking phrases?
在JVM Hotspot中,我们知道JVM需要在某些标记阶段停止mutator threads(STW),例如在年轻代和年老代初始标记阶段,GC类型CMS和G1在标记根时。
请问为什么在这些短语中必须要有STW?为了避免 mutator 和 mark 线程之间的竞争条件?
我们不能使用与并发标记短语相同的技术来避免 STW 吗?
当 CMS 收集器需要 运行 时,它需要标记根集。这是一组可直接从当前栈帧访问的对象加上静态引用。如果您允许 mutator 线程 运行 发生这种情况时,您很可能会错过引用,因为弹出堆栈帧并推送新堆栈帧。
标记根集后,GC 就有了一个准确的起点,可以从该起点跟踪应用程序代码中的所有其他可引用对象。这部分可以与增变器线程同时发生。
一旦(同时)跟踪了可达对象的完整图,就需要第二个 STW 重新标记阶段,以便可以将在并发标记阶段进行时所做的更改集成到有效对象引用列表中。
此时,可以使用并发清除阶段(因为现在已知所有有效对象)来更新有效对象之间可用内存区域的空闲列表。除非碎片变得太大或空闲 space 变得太小,否则不会进行压缩,此时会启动完整的压缩收集。
在JVM Hotspot中,我们知道JVM需要在某些标记阶段停止mutator threads(STW),例如在年轻代和年老代初始标记阶段,GC类型CMS和G1在标记根时。
请问为什么在这些短语中必须要有STW?为了避免 mutator 和 mark 线程之间的竞争条件?
我们不能使用与并发标记短语相同的技术来避免 STW 吗?
当 CMS 收集器需要 运行 时,它需要标记根集。这是一组可直接从当前栈帧访问的对象加上静态引用。如果您允许 mutator 线程 运行 发生这种情况时,您很可能会错过引用,因为弹出堆栈帧并推送新堆栈帧。
标记根集后,GC 就有了一个准确的起点,可以从该起点跟踪应用程序代码中的所有其他可引用对象。这部分可以与增变器线程同时发生。
一旦(同时)跟踪了可达对象的完整图,就需要第二个 STW 重新标记阶段,以便可以将在并发标记阶段进行时所做的更改集成到有效对象引用列表中。
此时,可以使用并发清除阶段(因为现在已知所有有效对象)来更新有效对象之间可用内存区域的空闲列表。除非碎片变得太大或空闲 space 变得太小,否则不会进行压缩,此时会启动完整的压缩收集。