Java G1GC - 卡表 (CT) 与记忆集 (RS)

问题描述 投票:0回答:2

为什么 g1 需要这两种数据结构?

我的理解是:

  1. CT保存了老年代引用的实际位置信息。
  2. RS是特定于每个区域的,每个区域都有一个与其关联的RS,它存储有关 指向该区域中对象的外部引用。因此,在导航 RS 时,实际位置 可以使用 CT 找到参考。

为什么RS不能保留所有信息而使用CT?

是不是因为否则会有太多重复数据存储在不同的RS中? 例如 - 年轻代有区域 A 和 B,这两个区域中的对象具有来自老一代的相同外部引用。 在这种情况下,与区域 A 和 B 关联的两个 RS 都会存储该冗余信息,这种解释正确吗?

java garbage-collection jvm g1gc
2个回答
7
投票

首先让我们把一些东西按正确的顺序排列。

Card Table
显示是否存在可能 传入该区域的引用。它确实有点“哈希”。对于卡表中的单个字节 - 旧区域中有many字节。这就像说如果(理论上)你有一个看起来像这样的牌桌(单张牌被标记为“脏”)

0 1 0 0 0 0

为此

1
(脏卡),在扫描年轻区域时,旧区域中也需要扫描特定的映射。

      0          1      0     .....

    0 - 512   512-1024  ...........

因此,脏卡对应于老年代中的某个部分(从 512 到 1024 字节),作为年轻代扫描的一部分,该部分也会被扫描。


G1 有区域,现在您需要了解

CT
RS
如何协同工作。假设 GC 此时扫描
Region1
,它会从该区域获取所有存活的内容并将其复制到
Region2
中。同时
Region2
引用了
Region3
。如果我们使用
CT
Region2
将被标记为“脏”(通过将特定卡片放入卡片表中)。

下一个周期要扫描

Region3
Region3
如何知道是否有 other 区域可能指向它?确实存在这样的情况:
Region2
引用了
Region3
。好吧,它可以查看
CT
并检查每张脏卡(以及这些脏卡对应的每个区域),并查看此处是否有来自任何这些区域的引用。想一想:为了清除
Region3
G1
必须查看整个
CT
。在最坏的情况下,它应该扫描整个堆 - 寻找单个区域。

因此:

Remembered Sets
。这些数据结构是根据
CT
所了解的信息,由异步线程填充的。当
Region2
被标记为脏时,异步线程将开始计算其
RS
。当需要扫描
Region3
时,其
RS
只会有带有
Region2
的条目。

因此,为了扫描单个区域,

G1
only需要查看该特定
RS


3
投票

我们看下图:

在年轻GC期间,E和G对象无法从GC Roots到达。因此它们可能被称为“死”对象。如果发生这种情况,将会导致不可预测的问题。

考虑到扫描整个堆太耗时,JVM使用rememberSet (RSet) 存储所有具有指向该区域内对象的指针的位置。下图显示了区域 5 的 RSet 示例。

根据 RSet 的不同粒度,有不同的实现。 为了简单起见,如果RSet只记录参考Region索引。 区域 5 的 RSet = {Region7, Region3}.

为了检查对象的活跃度,GC 仍然需要扫描整个 Region。最简单的优化应该是GC将一个Region划分成若干个小区域/页面。每个区域在卡牌表(CT)中都有一个标志。假设该区域包含指向外部区域的对象指针,则相应的标志被标记为dirty值。

所以card table就是用来表示是否包含老年代到年轻代的指针。它是特殊类型的 RSet。

© www.soinside.com 2019 - 2024. All rights reserved.