在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。所以标记的时候分为三种颜色,黑色,白色,灰色
黑色:表示对象已经被垃圾收集器访问过,并且它的所有引用也都扫描过,是安全存活的对象,如果有其他对象引用了黑色,那么无需重新扫描改对象
灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过
白色:表示对象尚未被垃圾收集器访问过。所以,最开始的时候,所有的对象都是白色,如果扫描一遍以后,还是白色,那么表示这个对象不可达,垃圾收集器
记忆集与卡表在新生代扫描时,可能会引用到老年代的对象,产生跨代引用,如果再去老年代扫描,效率太低了。
所以在新生代可以引入记录集(RememberSet)的数据结构(记录从非收集区到收集区的指针集合),避免把整个老年代加入GCRoots扫描范围。事实上并不只是新生代、老年代之间才有跨代引用的问题,所有涉及部分区域收集(PartialGC)行为的垃圾收集器,典型的如G1、ZGC和Shenandoah收集器,都会面临相同的问题。垃圾收集场景中,收集器只需通过记忆集判断出某一块非收集区域是否存在指向收集区域的指针即可,无需了解跨代引用指针的全部细节。hotspot使用一种叫做“卡表”(cardtable)的方式实现记忆集,也是目前最常用的一种方式。关于卡表与记忆集的关系,可以类比为Java语言中HashMap与Map的关系。卡表是使用一个字节数组实现:CARD_TABLE[],每个元素对应着其标识的内存区域一块特定大小的内存块,称为“卡页”。