public class ThreeColorRemark {
public static void main(String[] args) {
A a = new A(); //忽略报错信息
//开始做并发标记
D d = a.b.d; // 1.读
System.out.println("开始的d的内存地址"+d);
if (Objects.isNull(d)){
System.out.println("开始的d是null"+d);
}
a.b.d = null; // 2.写
System.out.println("中间的d的内存地址"+a.b.d);
if (Objects.isNull(a.b.d)){
System.out.println("中间的d是null"+a.b.d);
}
a.d = d; // 3.写
System.out.println("最后d的内存地址"+a.d);
if (Objects.isNull(a.d)){
System.out.println("最后的d是null"+a.d);
}
}
}
class A {
B b = new B();
D d = null;
}
class B {
C c = new C();
D d = new D();
}
class C {
}
class D {
}
讲一下代码运行与标记过程
1、首先CMS是有初始标记、并发标记、重新标记,其中初始标记、重新标记会STW。
相关信息可以看JVM垃圾收集器ParNew&CMS与底层三色标记算法详解_小丑竟是我自己-CSDN博客
2、当运代码执行到 A a = new A(); 时,
有了A的引用,对象A又引用了B,B引用了C、D
注意,在这一个时刻,Gcroots开始并发扫描,扫描到了A,并且扫描到了B,所以A变黑色,
扫描到了C,所以C变黑色,
但是还没有扫描到D,所以B是灰色,D是白色。
图应该是这样:(只是这一个时刻,并发扫描并没有结束)

可以这么理解:黑色被分析完了、灰色还没有分析完、白色是还没有被分析过。
默认都是白色。(分析指的是:Gcroots可达性分析)
3、在下一个时刻,b.d = null; a.d = d;



------------------------------------------------------------------------------------------------------------------------------
多标-浮动垃圾
所谓的写屏障,其实就是指在赋值操作前后,加入一些处理(可以参考AOP的概念):



读屏障

hotspot 的源码为(大致看下即可)

可以看到,逻辑和展示的伪代码相似,源代码使用了队列,做了异步处理。
-----------------------------------------------------------------------------------------------------------------
本文解析了并发垃圾回收中的三色标记机制,涉及黑色、灰色和白色对象状态,以及CMS的增量更新、G1的SATB策略和ZGC的读屏障。重点讲解了多标和漏标问题,以及如何通过写屏障和读屏障来确保垃圾回收的准确性。
1132





