Overview
G1的每个region都有一个Remember Set(Rset)
这个数据结构,用来保存别的region的对象对我这个region的对象的引用,通过Remember Set我们可以找到哪些对象引用了当前region的对象
参考这个文章
由于对我当前region对象的引用可能很多,也可能很少,G1会根据数量的变化来改变数据结构以达到节省空间的目的
第1种,哈希表
key是region的index,value是card数组。
card数组是个啥?
第2种,细粒度的PerRegionTable
这是一个Heap位图,每一位对应一个card
card又是个啥?
第3中,粗粒度位图
每一位代表对应的分区有引用到当前region,具体的对象还得在对应的分区里找
看代码吧那就
看的是jdk12源码
先看定义了哪些结构
src/hotspot/share/gc/g1/heapRegionRemSet.hpp
头部注释,介绍了Remember set
// Remembered set for a heap region. Represent a set of "cards" that
// contain pointers into the owner heap region. Cards are defined somewhat
// abstractly, in terms of what the "BlockOffsetTable" in use can parse.
就是一个set,记录了哪些card包含了指向我们当前region的指针。这个card是抽象的,BlockOffsetTable可以解析这个玩意儿?
再来一大段注释
// The "_coarse_map" is a bitmap with one bit for each region, where set
// bits indicate that the corresponding region may contain some pointer
// into the owning region.
// The "_fine_grain_entries" array is an open hash table of PerRegionTables
// (PRTs), indicating regions for which we're keeping the RS as a set of
// cards. The strategy is to cap the size of the fine-grain table,
// deleting an entry and setting the corresponding coarse-grained bit when
// we would overflow this cap.
// We use a mixture of locking and lock-free techniques here. We allow
// threads to locate PRTs without locking, but threads attempting to alter
// a bucket list obtain a lock. This means that any failing attempt to
// find a PRT must be retried with the lock. It might seem dangerous that
// a read can find a PRT that is concurrently deleted. This is all right,
// because:
//
// 1) We only actually free PRT's at safe points (though we reuse them at
// other times).
// 2) We find PRT's in an attempt to add entries. If a PRT is deleted,
// it's _coarse_map bit is set, so the that we were attempting to add
// is represented. If a deleted PRT is re-used, a thread adding a bit,
// thinking the PRT is for a different region, does no harm.
_coarse_map:粗粒度位图。是一个位图,每一位指向一个region,某一位设置为1代表有指针指向当前region。
_fine_grain_entries:细颗粒入口。哈希表,元素是PerRegionTables(PRTs),我们保存了RS(一个card的set),指向一些regions。策略是根据细粒度表的大小初始化一下,当我们容量超限的时候,删除entry并设置相应的粗粒度的bit。
我们混合使用 加锁机制 和 不加锁机制 。允许线程不加锁读PRTs,但是要修改bucket的话必须获得锁。这意味着任何查找PRT需要用重试获得锁。看起来,读操作可以找到一个并行的时候被删除的PRT是很危险的。但其实没啥问题,因为
1)我们实际上只在安全的时候释放PRT’s ???
2)我们找PRT’s是为了加entries。如果一个PRT被删除了,他相应的_coarse_map的位设置为1,所以我们尝试去加的那个就呈现了。如果删除的PRT被重用,一个线程加了一个bit,认为PRT是给另一个region的,也没有问题
强行翻译,是在看不懂😂