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

use*_*892 3 java garbage-collection jvm g1gc

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

我的理解是:

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

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

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

Eug*_*ene 7

让我们首先将一些事情按正确的顺序排列。ACard Table显示可能传入该区域的引用。它确实有点“哈希”。对于卡表中的单个字节 -旧区域中有许多字节。这就像说,如果(理论上)你有一个看起来像这样的牌桌(单张牌被标记为“脏”)

0 1 0 0 0 0
Run Code Online (Sandbox Code Playgroud)

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

      0          1      0     .....

    0 - 512   512-1024  ...........
Run Code Online (Sandbox Code Playgroud)

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


G1 有多个区域,现在您需要了解如何CT协同RS工作。假设Region1此时 GC 进行扫描,它会从该区域获取所有存活的内容并将其复制到Region2. 同时Region2有参考文献Region3。如果我们使用CT,Region2将被标记为“脏”(通过将特定卡放入卡表中)。

下一个周期要扫描Region3。如何Region3知道是否有其他区域可能指向它?确实存在这样的情况:Region2有引用到Region3. 好吧,它可以查看CT并检查每个脏卡(以及这些脏卡对应的每个区域),并查看此处是否有来自任何这些区域的引用。想一想:要想清楚Region3G1就得看整体 CT。在最坏的情况下,它应该扫描整个堆 - 寻找单个区域。

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

因此,为了扫描单个区域,G1 需要查看该特定的RS.