标准CMS算法首先使应用程序经历STW暂停以计算GC根集。然后,它会继续执行mutator线程,并且应用程序线程和收集器线程会同时运行,直到完成标记为止。由mutator线程更新的任何指针存储都受到写屏障的保护,该写屏障会将该指针引用添加到写队列中。
[标记阶段完成后,我们进入“标记阶段”:然后它必须调查此写队列,并标记在那里发现的尚未标记的任何内容。
所有这些都是有道理的。我不明白的是为什么我们需要:
[在CMS A Generational Mostly-concurrent Garbage Collector上阅读原始论文之一时,可以看到:
最初的主要是并行算法,由Boehm等。 [5]是并发的“三色”收集器[9]。它使用写屏障导致堆对象字段的更新将包含的对象着色为灰色。它的主要创新是它通过允许根位置(全局变量,堆栈,寄存器)来权衡完整的并发以提高吞吐量,通常比堆位置更频繁地进行更新,而无需使用障碍来进行写入三色不变式。
它看起来像是权衡取舍,这是有意识的决定,不涉及写屏障中堆栈上发生的事情?
谢谢
- 此标记阶段是否从头开始(包括所有线程堆栈)重新计算了GC根集-这样做是否会导致算法错误,因为它将实际存在的可访问对象标记为要回收的垃圾?
[不,三色标记标记了活动对象(没有标记的对象,然后用尽了“灰色”设置的对象将无法访问)。备注将重新发现的根对象与所有由写屏障捕获的引用一起添加到“灰色”集中,这样可以将更多对象标记为活动对象。
总结来说,在CMS标记后,所有活动对象都被标记了,尽管某些死对象也可以被标记。
- 此标记阶段是否是另一个STW事件(也许是因为必须分析所有线程堆栈?)
是,这是HotSpot JVM中CMS算法中的STW暂停(您可以了解有关CMS阶段here的更多信息。]
并回答标题中的问题
为什么并发标记扫描(CMS)标记阶段需要重新检查线程堆栈,而不是仅仅查看变量的写入队列?
CMS不使用“ mutator的写入队列”,它使用卡标记写入障碍(与young generation copy collector共享。]]
通常,所有使用写屏障的算法都需要STW暂停,以避免出现“乌龟和箭头”悖论。
CMS启动初始三色标记。然后标记完成的“一些”活动对象,但是由于并发修改,标记可能会遗漏某些对象。尽管写屏障捕获了所有突变,因此“预清理”将所有突变引用添加到“灰色”集,并继续标记到达的丢失对象。尽管此过程趋于收敛,但需要停止mutator的最终说明。