G1算法中的记忆集是做什么用的?

What is remembered set in G1 algorithms used for?

刚看了一些关于G1算法的博客

remembered-set 的用法让我很困惑。

这是我的想法:

既然我们可以使用 DFS 遍历 GC-Roots 中的每个引用,为什么我们需要 remembered-set?

导致所有的博客都说我们使用remembered-set的原因是我们不需要检查每个区域来查看是否有被GC-Roots引用的对象

你需要先了解 Card Table 是什么,IMO。如果有从 old generation 回到 young 的引用,你如何只扫描 young generation 区域并清理它?您需要 "track" 这些连接存在的确切位置 - 因此在扫描时 young generation 您可以在不破坏堆的情况下清理它。

想一想:你不能将一个对象 A 标记为删除,如果它现在在年轻一代中,如果有对它的引用 B,来自 old generation .但请记住,现在 - 您仅 在年轻的集合中。因此,为了跟踪这些 "connections",实施了 Card Table。这张卡片的每一位 table 表示老年代的某个部分是 "dirty",意思是 在扫描年轻代的同时也扫描老年代的那部分

你为什么需要那个?扫描 young 的全部目的是扫描堆中的一小部分,而不是全部。 card table 实现了这一点。

G1 有区域。如果您正在扫描 regionA 并且发现它有指向其他 regionB 的指针怎么办?仅将此信息放在 Card Table 中是不够的。您的卡 table 只会知道 regionA,而您下次扫描 regionB - 您怎么知道您应该也扫描 regionA?如果你不这样做,显然堆完整性被破坏了。

因此:remembered sets。这些集合由一个异步线程填充:它扫描 card table 并根据该信息它还扫描这些 "dirty" 区域有指针的位置。它会跟踪 regionA -> regionB 连接。每个区域都有自己的 remembered set

所以当你到达GC需要发生的地步时,当扫描regionB时你也查看它的remembered set并发现你还需要扫描regionA


在实践中,这就是 G1 成为一代人的原因:这些 remembered sets 结果是 巨大 。如果你把堆分成 youngold,就没有必要保持年轻代之间的联系,反正你一次扫描它们,从而消除了这些集合大小的消耗。 G1 想要保持 200ms(默认)承诺 - 为此,您需要一次扫描年轻一代 (因为区域之间没有连接在 remembered sets 中,否则堆完整性消失了),但同时如果你让年轻一代变小 - remembered sets 的大小将会很大。

因此,触及这些设置是一个工程奇迹,恕我直言。