CMS 清理流程
三色标记
概述
三色标记其实就是用三种颜色区分不同的内存区域。
- 黑色标记:自己已经标记,直接引用的对象区域已经标记
- 灰色标记:自己标记完成,但引用区域没来得及标记
- 白色标记:没有遍历到的区域,可以理解为没有标记
CMS在每次进行标记的时候。从根root广度优先遍历。第一次遍历根root最终被标记为黑色,且引用对象标记为灰色。
再次遍历时黑色区域引用区域也已经标记,则不会再次扫描标记,灰色区域需要进行扫描并最终标记为黑色区域。白色区域<未标记>的认为是垃圾,进行清理。
可能存在的问题已经解决
假设
A:一个黑色区域
B:一个灰色区域
C:一个白色区域<未被扫描>
浮动垃圾问题
概述
原本A引用B,但在A标记为黑色后,A对B的引用断开,没有指向B的引用后,B应该为白色区域,但已经标记灰色区域。这种情况,B第一次垃圾回收不会被回收,这种情况称为浮动垃圾
但是浮动垃圾并不会有实质性的影响,因为下次垃圾回收会重新标记,则会被回收。
漏标问题
概述
原本A引用B,B引用C,在A被标记为黑色后,A建立了指向C的引用,且B指向C的引用断开。此时A已经被标记为黑色,则不会再便利A的引用,且B对C的引用已经断开。这样会造成C未被标记,被垃圾回收,造成空指针问题。
解决方法:
CMS解决方式:
当发生A引用C<黑色对象指向了白色对象>的情况。此时将A标记为灰色。并且在全部标记结束后,会有一个remark阶段,必须从头扫描一遍。发生在重新标记阶段,所以在这个阶段必须STW。
G1解决方式 :
当发生B指向C的引用<指针>断开的时候。将这个引用<指针>记录在一个特定区域。垃圾回收线程在扫描的时候会查看这个区域的增量数据。发现有增量数据。会看C此时还有没有对象指向他,如果有则将区域C标记为灰色。否则不标记<视为可回收垃圾>。