美团面试官问我: ZGC 的 Z 是什么意思 (3)

如果是的话修正对象的引用,按照上面的例子,不仅 a 能得到最新的引用地址,obj.foo 也会被更新,这样下次访问的时候一切都是正常的,就没有消耗了。

下图展示了读屏障的效果,其实就是转移的时候找地方记一下即 forwardingTable,然后读的时候触发引用的修正。

美团面试官问我: ZGC 的 Z 是什么意思

这种也称之为“自愈”,不仅赋值的引用时最新的,自身引用也修正了。

染色指针和读屏障是 ZGC 能实现并发转移的关键所在

ZGC 回收流程解析

ZGC 的步骤大致可分为三大阶段分别是标记、转移、重定位。

标记:从根开始标记所有存活对象

转移:选择部分活跃对象转移到新的内存空间上

重定位:因为对象地址变了,所以之前指向老对象的指针都要换到新对象地址上。

并且这三个阶段都是并发的。

这是意识上的阶段,具体的实现上重定位其实是糅合在标记阶段的

在标记的时候如果发现引用的还是老的地址则会修正成新的地址,然后再进行标记。

简单的说就是从第一个 GC 开始经历了标记,然后转移了对象,这个时候不会重定位,只会记录对象都转移到哪里了。

在第二个 GC 开始标记的时候发现这个对象是被转移了,然后发现引用还是老的,则进行重定位,即修改成新的引用。

所以说重定位是糅合在下一步的标记阶段中。

美团面试官问我: ZGC 的 Z 是什么意思

我再简单说一下十个步骤。

不过步骤里有些不影响整体回收流程的,我就不多加分析了。

这篇文章的目的不是深入 ZGC 实现的细节,而是了解 ZGC 大致的突出点和简单流程即可

因此想知道细节的自行查阅,或者可以看看我文末推荐的书籍。

初始标记

这个阶段其实大家应该很熟悉,CMS、G1 都有这个阶段,这个阶段是 STW 的,仅标记根直接可达的对象,压到标记栈中

当然还有其他动作,比如重置 TLAB、判断是否要清除软引用等等,不做具体分析。

并发标记

就是根据初始标记的对象开始并发遍历对象图,还会统计每个 region 的存活对象的数量。

这个并发标记其实有个细节,标记栈其实只有一个,但是并发标记的线程有多个。

为了减少之间的竞争每个线程其实会分到不同的标记带来执行。

你就理解为标记栈被分割为好几块,每个线程负责其中的一块进行遍历标记对象,就和1.7 Hashmap 的segment 一样。

那肯定有的线程标记的快,有的标记的慢,那么先空闲下来的线程会去窃取别人的任务来执行,从而实现负载均衡。

看到这有没有想到啥?没错就是 ForkJoinPool 的工作窃取机制!

再标记阶段

这一阶段是 STW 的,因为并发阶段应用线程还是在运行的,所以会修改对象的引用导致漏标的情况。

因此需要个再标记阶段来标记漏标的那些对象。

如果这个阶段执行的时间过长,就会再次进入到并发标记阶段,因为 ZGC 的目标就是低延迟,所以一有高延迟的苗头就得扼制。

这个阶段还会做非强根并行标记,非强根指的是:系统字典、JVMTI、JFR、字符串表。

有些非强根可以并发,有些不行,具体不做分析。

非强引用并发标记和引用并发处理

就是上一步非强根的遍历,然后引用就软引用、弱引用、虚引用的一些处理。

这个阶段是并发的。

重置转移集

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwyyd.html