三色标记漏标
如果发生漏标了会怎样?
会导致本该存活的对象,因未被标记为黑色而被回收,严重影响程序功能。
多标了会有什么影响吗?
只是会产生了浮动垃圾,占用了一点点内存空间,等待下次GC时处理,不影响全局。
产生漏标问题的两个条件
1. 黑色对象指向了白色对象
2. 灰色对象指向白色对象的引用消失
这两个条件同时满足
才会产生漏标。
第一个条件:有至少一个黑色对象在自己被标记之后指向了这个白色对象
黑色对象代表已被扫描且不再参与GC处理。假设在GC过程中,黑色对象A在扫描完成之后,新建了对白色对象B的引用,而B尚未被标记(白色)。由于黑色对象不会再被扫描,这个引用关系就不会被发现,导致白色对象B未被标记,从而在GC结束时错误地被回收。
第二个条件:所有灰色对象在自己引用扫描完成之前删除了对白色对象的引用
灰色对象表示仍然在被扫描的对象。如果一个灰色对象在扫描过程中移除了对白色对象的引用,那么在后续扫描中,它不会将这个白色对象标记为可达。这样白色对象依然保持白色状态,最终会被回收。
为什么需要同时满足这两个条件?
单独满足第一个条件时:
假设仅有第一个条件满足,即黑色对象在标记后指向了一个白色对象,但灰色对象依然有指向这个白色对象的引用。由于灰色对象仍在扫描过程中,它最终会将白色对象标记为可达,所以不会漏标。因此,单独满足第一个条件时,白色对象最终还是会被正确标记。
单独满足第二个条件时:
如果只有第二个条件满足,即所有灰色对象在扫描结束前移除了对白色对象的引用,但没有黑色对象新建对该白色对象的引用,那么白色对象确实变成了不可达,它应该被正确回收,也不会造成漏标。
两个条件同时满足时:
当黑色对象在标记后指向白色对象(第一个条件),而灰色对象又移除了对白色对象的引用(第二个条件),这时就没有任何灰色或黑色对象可以再标记这个白色对象,导致GC认为白色对象是不可达的并错误回收它。这正是三色标记算法中经典的漏标问题场景。
漏标问题的本质
三色标记算法的一个核心问题就是如何避免这种错误回收,特别是在GC进行时,程序仍然可以对引用关系进行修改。这就是为什么一般会引入"写屏障"或"增量更新"机制,以确保黑色对象引用到白色对象时,能够及时通知GC,使其重新标记那些原本漏掉的对象。
总结来说,同时满足这两个条件会导致GC发生漏标。如果只有一个条件满足,白色对象依然有机会被灰色对象标记为可达,避免错误回收。