我刚刚阅读了一些关于 G1 算法的博客。
记住集合的用法让我感到困惑。
这是我的想法:
既然我们可以使用 DFS 遍历来自 GC-Roots 的每个引用,为什么我们需要记住集?
导致所有的博客都说我们使用remembered-set的原因是我们不需要检查每个region来查看是否有GC-Roots引用的对象
最佳答案
您需要了解什么Card Table
首先,海事组织。你怎么只扫描young generation
区域并清理它,如果有来自 old generation
的引用返回 young
?您需要准确地“跟踪”这些连接所在的位置 - 因此在扫描时 young generation
你可以在不破坏堆的情况下清理它。
想一想:您不能将对象标记为移除 A
现在是年轻代,如果有引用B
到它,来自 old generation
.但现在请记住——你只是在年轻的系列中。所以要跟踪这些“连接”Card Table
被执行。这张卡片表中的每一位都表示老年代的某个部分是“脏的”,这意味着在扫描年轻代的同时也扫描老年代的那部分。
你为什么需要那个?扫描年轻的整个点是扫描堆的一小部分,而不是全部。此 card table
做到了这一点。G1
有地区。如果您正在扫描怎么办 regionA
你会看到它有指向其他一些 regionB
的指针?只需将此信息放入 Card Table
是不足够的。你的牌 table 只会知道regionA
,下次扫描时 regionB
- 你怎么知道你应该扫描 regionA
还?如果你不这样做,显然堆完整性被破坏了。
因此:remembered sets
.这些集合由一个异步线程填充:它扫描 card table
并根据该信息,它还扫描这些“脏”区域的指针指向的位置。它跟踪该 regionA -> regionB
联系。每个地区都有自己的remembered set
.
所以当你到达GC需要发生的点时,扫描regionB
时你也看看它的remembered set
并发现您还需要扫描regionA
.
实际上,这就是为什么 G1
成为世代:这些 remembered sets
结果是巨大的。如果在young
中划分堆和 old
,没有必要保持年轻代之间的联系,无论如何你都会一次扫描它们,从而消除这些集合大小的问题。 G1
想保留那个 200ms
(默认)promise - 为此,您需要一次扫描所有年轻代(因为 remembered sets
中的区域之间没有连接,否则堆完整性将消失),但同时如果您使年轻代变小 - remembered sets
的尺寸会很大。
因此,恕我直言,触摸这些设置是一个工程奇迹。
关于java - G1算法中的 memset 有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61936621/