为什么 Concurrent-Mark-Sweep (CMS) 注释阶段需要重新检查线程堆栈,而不是仅仅查看修改器的写入队列?

Why does Concurrent-Mark-Sweep (CMS) remark phase need to re-examine the thread-stacks instead of just looking at the mutator's write-queues?

标准 CMS 算法首先使应用程序经历 STW 暂停以计算 GC 根集。然后它会同时恢复增变器线程以及应用程序和收集器线程 运行,直到标记完成。由修改器线程更新的任何指针存储都受到写入屏障的保护,该屏障会将指针引用添加到写入队列。

标记阶段完成后,我们将继续进行重新标记阶段:然后它必须查看此写入队列并继续标记它在那里找到但尚未标记的任何内容。

所有这些都是有道理的。我不明白的是为什么我们需要:

  1. 让这个重新标记阶段从头开始重新计算 GC 根集(包括所有线程堆栈)——不这样做会导致算法不正确,因为它将实际存在的和可访问的对象标记为垃圾被回收?;
  2. 这个重新标记阶段是否是另一个 STW 事件(也许这是因为必须分析所有线程堆栈?)

当阅读一篇关于 CMS 的原始论文时 A Generational Mostly-concurrent Garbage Collector 可以看到:

The original mostly-concurrent algorithm, proposed by Boehm et al. [5], is a concurrent “tricolor” collector [9]. It uses a write barrier to cause updates of fields of heap objects to shade the containing object gray. Its main innovation is that it trades off complete concurrency for better throughput, by allowing root locations (globals, stacks, registers), which are usually updated more frequently than heap locations, to be written without using a barrier to maintain the tricolor invariant.

看起来这只是一个有意识的决定的权衡,不涉及写屏障中堆栈上发生的事情?

谢谢

  1. Have this remarking phase recalculate the GC-root-set from scratch (including all thread stacks) -- does not doing this result in an incorrect algorithm, in the sense of it marking actually live and reachable objects as garbage to be reclaimed?

不,三色标记标记活objects(objects到那时未标记"grey"设置已用完无法访问)。备注将重新发现的根 objects 添加到 "grey" 集以及 write-barrier 捕获的所有引用,因此更多 objects 可以标记为活动。

总而言之,在 CMS 评论后,所有活的 objects 都被标记了,尽管一些死的 objects 也可以被标记。

  1. Have this remarking phase be another STW event (maybe this is because of having to analyse all the thread-stacks?)

是的,备注是 HotSpot JVM 中 CMS 算法中的 STW 暂停(您可以阅读有关 CMS 阶段的更多信息 here)。

并回答标题中的问题

Why does Concurrent-Mark-Sweep (CMS) remark phase need to re-examine the thread-stacks instead of just looking at the mutator's write-queues?

CMS 不使用 "mutator's write-queues",它使用卡片标记写入屏障(与 young generation copy collector 共享)。

通常所有使用写屏障的算法都需要 STW 暂停以避免 "turtle and arrow" 悖论。

CMS 开始初始 tri-color 标记。然后就完成了"some"活objects的标记,但是由于并发修改标记可能会漏掉某些objects。尽管 write-barrier 捕获所有突变,因此 "pre clean" 将所有突变引用添加到 "gray" 集并恢复标记到达未命中 objects。尽管要使此过程收敛,需要在停止增变器的情况下进行最后的评论。