【问题标题】: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?为什么 Concurrent-Mark-Sweep (CMS) remark 阶段需要重新检查线程堆栈,而不是仅仅查看 mutator 的写入队列?
【发布时间】:2019-12-01 14:59:24
【问题描述】:

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

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

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

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

在阅读 CMS A Generational Mostly-concurrent Garbage Collector 上的一篇原始论文时,可以看到:

最初的大部分并发算法,由 伯姆等人。 [5],是一个并发的“三色”收集器 [9]。它 使用写屏障来更新堆对象的字段 将包含的对象设为灰色。它的主要创新是 它通过允许根位置(全局、堆栈、寄存器)来权衡完全并发以获得更好的吞吐量, 通常比堆位置更频繁地更新,在不使用屏障维护的情况下编写 三色不变量。

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

谢谢

【问题讨论】:

  • 这个问题一点也不坏。请记住,CMS 已被弃用,没有人支持它......

标签: garbage-collection jvm vm-implementation hotspot


【解决方案1】:
  1. 让这个重新标记阶段从头开始重新计算 GC 根集(包括所有线程堆栈)——这样做不会导致算法不正确,因为它会将实际活动且可访问的对象标记为要回收的垃圾?

不,三色标记标记活动对象(在“灰色”集耗尽之前未标记的对象是无法访问的)。备注将重新发现的根对象与所有被写屏障捕获的引用一起添加到“灰色”集,因此可以将更多对象标记为活动。

总而言之,在 CMS 备注之后,所有活动对象都会被标记,尽管也可能会标记一些死对象。

  1. 此重新标记阶段是否是另一个 STW 事件(可能是因为必须分析所有线程堆栈?)

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

并回答标题中的问题

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

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

通常所有使用写屏障的算法都需要 STW 暂停以避免“乌龟和箭”悖论。

CMS 开始初始三色标记。然后它完成了“一些”活动对象的标记,但由于并发修改标记可能会错过某些对象。尽管 write-barrier 捕获所有突变,因此“预清理”将所有突变引用添加到“灰色”集并继续标记到达错过的对象。尽管要使此过程收敛,但需要在 mutator 停止的情况下进行最后的评论。

【讨论】:

  • 现在我明白了。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-03
  • 1970-01-01
  • 1970-01-01
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多