我刚刚阅读了一些关于 G1 算法的博客。
记住集合的用法让我感到困惑。
这是我的想法:
既然我们可以使用 DFS 遍历来自 GC-Roots 的每个引用,为什么我们需要记住集?
导致所有博客都说我们使用remembered-set的原因是我们不需要检查每个region来查看是否有GC-Roots引用的对象
您首先需要了解什么Card Table是 IMO。如果有从back 到 的引用,你如何只 扫描young generation区域并清理它?您需要准确地“跟踪”这些连接所在的位置 - 因此在扫描时您可以在不破坏堆的情况下清理它。old generationyoungyoung generation
想一想:A如果有B对它的引用,则不能将现在处于年轻代的 Object 标记为删除old generation。但现在还记得正确的-你是年轻的集合中唯一。因此,为了跟踪这些“连接” Card Table,实现了一个。这张卡片表中的每一位都表示老年代的某个部分是“脏的”,这意味着在扫描年轻代的同时也扫描老年代的那部分。
你为什么需要那个?扫描年轻的整个点是扫描堆的一小部分,而不是全部。这card table实现了。
G1有地区。如果您正在扫描regionA并且看到它有指向其他文件的指针regionB怎么办?简单地将这些信息放在 中Card Table是不够的。您的牌桌只会知道regionA,并且下次您扫描时regionB- 您怎么知道您也应该扫描regionA?如果你不这样做,显然堆完整性被破坏了。
因此:remembered sets。这些集合由异步线程填充:它扫描card table并根据该信息扫描这些“脏”区域的指针指向的位置。它会跟踪该regionA -> regionB连接。每个地区都有自己的remembered set。
因此,当您到达需要进行 GC 的点时,在扫描时regionB您也会查看它remembered set并发现您还需要扫描regionA.
在实践中,这就是为什么G1成为代际的原因:这些remembered sets结果是巨大的。如果将堆划分为young和old,则无需保持年轻代之间的连接,无论如何您都可以一次扫描它们,从而消除这些集合大小的问题。G1想要保持那个200ms(默认)承诺 - 要做到这一点,你需要一次扫描年轻代(因为区域之间没有连接remembered sets,否则堆完整性消失了),但同时如果你让年轻代变小- 的大小remembered sets会很大。
因此,恕我直言,触摸这些设置是一个工程奇迹。
| 归档时间: |
|
| 查看次数: |
782 次 |
| 最近记录: |