三色标记法
JVM(Java虚拟机)中的三色标记法是一种用于垃圾收集(Garbage Collection, GC)的算法,尤其在CMS(Concurrent Mark Sweep)和G1(Garbage First)等并发收集器中广泛使用。该算法通过将对象标记为三种不同的颜色来追踪和识别垃圾对象,从而在不发生或尽可能短地发生STW(Stop The World,即全线程停顿)的情况下进行垃圾收集。以下是三色标记法的详细介绍:
三色标记法的颜色定义
- 白色:表示对象尚未被垃圾收集器访问过。在可达性分析刚开始的阶段,所有的对象都是白色的。如果在分析结束的阶段,对象仍然是白色的,则表示该对象不可达,即被认为是垃圾。
- 灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过。在扫描过程中,垃圾收集器会从灰色对象出发,继续扫描其引用的其他对象。
- 黑色:表示对象已经被垃圾收集器访问过,并且这个对象的所有引用都已经被扫描过。黑色对象是安全存活的,不会被作为垃圾回收。
三色标记法的流程
- 初始状态:所有对象都是白色的。
- 根节点标记:将GC Roots(如线程栈、静态变量等)直接可达的对象标记为灰色,并将它们放入一个待处理的队列中。
- 并发标记:从待处理队列中取出一个灰色对象进行扫描。扫描当前对象的所有引用,如果子节点是白色的,就将其标记为灰色,并放入待处理队列中;如果子节点已经是灰色或黑色的,则不进行处理。将当前节点标记为黑色。重复此过程,直到待处理队列为空。
- 垃圾清理:在标记过程结束后,所有剩余的白色对象都是不可达的,可以被回收。
并发标记过程中的问题与挑战
- 浮动垃圾:在并发标记过程中,由于用户线程的运行,可能会产生新的垃圾对象或导致部分已标记为黑色或灰色的对象变为垃圾。这些垃圾对象被称为浮动垃圾。浮动垃圾不会影响垃圾回收的正确性,但会增加内存的占用,可以在下一轮垃圾回收中清除。
- 漏标问题:漏标是指应该被标记为存活的对象(即需要的对象)由于某些原因未被标记,导致被错误地回收。漏标问题在并发标记过程中尤为严重,因为它会直接影响程序的正确性。JVM通过读写屏障(如增量更新和SATB)等机制来解决漏标问题。
读写屏障
- 增量更新(Incremental Update):当黑色对象被插入新的指向白色对象的引用时,将该引用记录下来。在并发标记结束后,根据记录重新扫描这些被新引用的白色对象,确保它们被正确标记。CMS收集器采用这种方法。
- SATB(Snapshot At The Beginning):在并发标记开始时记录对象的快照,并在并发标记过程中使用这些快照来避免漏标。当对象的引用发生变化时(无论是新增还是删除),都通过写屏障来记录这些变化。G1收集器采用SATB+写屏障的方式来避免漏标。
三色标记法通过精细的对象标记和高效的并发处理,使得JVM能够在不影响或尽可能少地影响应用程序运行的情况下进行垃圾收集,提高了系统的整体性能和响应速度。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿鑫的博客ッ!
评论



