1. 什么是卡表
在新生代做GCRoots可达性扫描过程中可能会碰到跨代引用的对象,这种如果又去对整个老年代再去扫描效率太低了。
为此,在新生代可以引入记录集
(Remember Set)的数据结构(记录从非收集区到收集区的指针集合),避免把整个老年代加入GCRoots扫描范围。事实上并不只是新生代、 老年代之间才有跨代引用的问题, 所有涉及部分区域收集(Partial GC) 行为的垃圾收集器, 典型的如G1、 ZGC和Shenandoah收集器, 都会面临相同的问题。
垃圾收集场景中,收集器只需通过记忆集判断出某一块
非收集区域是否存在指向收集区域的指针即可,无需了解跨代引用指针的全部细节。
hotspot
使用一种叫做“卡表
”(cardtable)的方式实现记忆集,也是目前最常用的一种方式。记忆集其实是一种“抽象”的数据结构,卡表就是记忆集的一种具体实现,关于卡表与记忆集的关系,可以类比为Java语言中HashMap与Map的关系。
卡表是使用一个字节数组
实现:CARD_TABLE[ ],每个元素对应着其标识的内存区域一块特定大小的内存块,称为“卡页”。hotSpot使用的卡页是2^9大小,即512字节
一个卡页中可包含多个对象,只要有一个对象的字段存在跨代指针,其对应的卡表的元素标识就变成1,表示该元素变脏,否则为0。
GC时,只要筛选本收集区的卡表中变脏的元素加入GCRoots里
。
2. 卡表的维护
卡表变脏上面已经说了,但是需要知道如何让卡表变脏,即发生引用字段赋值时,如何更新卡表对应的标识为1。
Hotspot使用写屏障
维护卡表状态。