跨代引用举例:假如要现在进行一次只局限于新生代区域内的收集(Minor GC),但新生代中的对象是完全有可 能被老年代所引用的,为了找出该区域中的存活对象,不得不在固定的GC Roots之外,再额外遍历整个老年代中 所有对象来确保可达性分析结果的正确性,反过来也是一样。 并不只是新生代、老年代之间才有跨代引用的问题,所有涉及部分区域收集(Partial GC)行为的垃圾收集器,典 型的如G1、ZGC和Shenandoah收集器,都会面临相同的问题,JVM 为了用尽量少的资源消耗解决跨代引用下的垃圾回收问题,引入了记忆集。
记忆集是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构。 在垃圾收集的场景中,收集器只需要通过记忆集判断出某一块非收集区域是否存在有指向了收集区域的指针就可以了,并不需要了解这些跨代指针的全部细节。目前最常用的一种记忆集实现形式种称为“卡表”,卡表中的每个记录精确到一块内存区域(每块内存区域称之为卡页),该区域内有对象含有跨代指针。
一个卡页的内存中通常包含不止一个对象,只要卡页内有一个(或更多)对象的字段存在着跨代指针,那就将对 应卡表的数组元素的值标识为1,称为这个元素变脏(Dirty),没有则标识为0。在垃圾收集发生时,只要筛选出 卡表中变脏的元素,就能轻易得出哪些卡页内存块中包含跨代指针,把它们加入GC Roots中一并扫描。