比如在对某个区域进行回收时,首先从GC ROOT开始遍历可直达这些区域中的对象,可由于晋升或者移动的原因,这些区域中的某些对象移动到了其他区域,可是移动之后仍然保持着对原区域对象的引用;那么此时原区域中被引用的对象对GC ROOT来说并不能“直达”,他们被其他对象的区域引用,这个发起引用的其他对象对于GC ROOT可达。这种情况下,如果想正确的标记这种GC ROOT不可直达但被其他区域引用的对象时就需要遍历所有区域了,代价太高。
如下图所示,如果此时对区域A进行回收,那么需要标记区域A中所有存活的对象,可是A中有两个对象被其他区域引用,这两个灰色的问号对象在区域A中对GC ROOTS来说是不可达的,但是实际上这两个对象的引用对象被GC ROOTS引用,所以这两个对象还是存活状态。此时如果不将这两个对象标记,那么就会导致标记的遗漏,可能造成误回收的问题
RememberedSet(简称RS或RSet)就是用来解决这个问题的,RSet会记录这种跨代引用的关系。在进行标记时,除了从GC ROOTS开始遍历,还会从RSet遍历,确保标记该区域所有存活的对象(其实不光是G1,其他的分代回收器里也有,比如CMS)
如下图所示,G1中利用一个RSet来记录这个跨区域引用的关系,每个区域都有一个RSet,用来记录这个跨区引用,这样在进行标记的时候,将RSet也作为ROOTS进行遍历即可
所以在对象晋升的时候,将晋升对象记录下来,这个存储跨区引用关系的容器称之为RSet,在G1中通过Card Table来实现。
注意,这里说Card Table实现RSet,并不是说Card Table是RSet背后的数据结构,只是RSet中存储的是Card Table数据