java - G1算法中的记忆集是用来干什么的?
我刚刚看了一些关于G1算法的博客。
我对 remembered-set 的用法感到很困惑。
我是这么认为的。
既然我们可以用DFS来遍历GC -Roots中的每一个引用 那为什么我们还需要remembered -set?
因为所有的博客都说,我们之所以使用remembered-set,是因为我们不需要检查每一个区域,看看是否有一个对象被GC-Roots引用了。
【回答】:
你需要了解什么是 Card Table
是第一的,IMO。你如何扫描 只是 young generation
区域,并对其进行清理,如果有来自于 old generation
回到 young
? 你需要准确地 "跟踪 "这些连接存在的位置--所以在扫描时 young generation
你可以在不破坏堆的情况下清理它。
想一想:你不能把一个对象标记为要移除的对象 A
现在年轻一代的人,如果有一个参照物的话 B
到它,从 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
将是大。
因此,触及这些设置,我认为是一个工程奇迹。