把Gcroots可达性分析遍历对象过程中遇到的对象, 按照“是否访问过”这个条件标记成以下三种颜色:
- 黑色:被垃圾收集器扫描完毕,对象内的所有引用都被扫描完成,之后不会在被扫描
- 灰色 :被垃圾收集器访问过,但还至少有一个引用没有被扫描
- 白色:尚未被垃圾收集器访问过。
起初所有对象都是白色的,注意,黑色对象永远不可能直接指向白色对象,只能指向灰色对象或者是黑色对象
在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。
多标 浮动垃圾
在CMS和G1这种垃圾收集器中并发标记的过程中由于用户线程也在跑,那么可能刚才标记为非垃圾对象就变为垃圾对象了,那么这些对象就是多标。
漏标
在并发标记的过程中,一个Gcroot内成员变量所引用到的B对象他的成员变量又引用别的D对象,B对象的调用D对象的成员变量在还没有被扫描到之前被清空了,那么这个时候Gcroot对象(已经变为黑色)再引用上这个D对象,那么这个对象就不会被扫描到,这个非垃圾对象会被当做垃圾对象误删除。
漏标会导致被引用的对象被当成垃圾误删除,这是严重bug,必须解决,有两种解决方案:
增量更新:
增量更新就是当黑色对象插入新的指向白色对象的引用关系时, 就将这个新插入的引用记录下来, 等并发扫描结束之后, 再将这些记录过的引用关系中的黑色对象为根, 重新扫描一次。可以简单理解为 黑色对象一旦新插入了指向白色对象的引用之后, 它就变回灰色对象了。在重新标记时会被从新扫描
原始快照:
就是当灰色对象要删除指向白色对象的引用关系时, 就将这个要删除的引用记录下来, 在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根, 重新扫描一次,这样就能扫描到白色的对象,将白色对象直接标记为黑色,可能会被当作浮动垃圾。