ZGC简介

1. 介绍

java11介绍了一个优秀的垃圾回收实现ZGC,ZGC是一款以低延迟为首要目标、基于paper内存布局、不设分代的并发垃圾收集器。

相比于其他垃圾回收器,ZGC有着不同的特点:

  1. 低时延,在垃圾回收过程中,只有与root有关的处理才会STW,时延不是随着堆大小而增加,低时延是最大的特点,也是ZGC的设计目标

  2. 内存分区管理

    支持不同的分区粒度,有小页面、中页面、大页面之分。

  3. 不分代的垃圾回收

    在标记阶段,对全量内存进行标记,在回收的时候,选择回收价值更大的页面

  4. Colored Pointer,在引用上利用标记位来表示对象不同的状态,并利用多视图映射将不同的虚拟地址映射岛同一物理地址

  5. 使用Load-Barrier,来完成并发标记和并发重定位

  6. 支持NUMA,进来把对象分配在访问速度比较快的地方

2. 内存管理

ZGC的内存管理和G1类似,使用分区管理。在G1中,一个分区称为一个region,大小是固定的。在ZGC中分区叫做page,分为小、中、大

3. ZGC流程

ZGC回收流程包括6个阶段,可分为标记和重定位两个过程

标记的方法很多种,1. 弄个map,key为对象地址,value为对象状态;2. 在对象头,记录对象状态。3. ZGC采用的是 对引用进行标记,把对象状态,记录在引用的几个bit上,即“Colored Pointer”

4. 标记过程

  1. 开始标记,STW,这个阶段,GC线程完成对根引用的标记,由于跟引用数量通常很少,所以这个阶段很短
  2. 并发标记,GC线程从根引用开始深度优先遍历对象图,标记达到的每一个对象。工作线程的Load-Barrier检测到未标记的引用时,也会标记。还会对上一次GC中没有完成重映射的引用,进行重映射,即Remap。
  3. 结束标记,也是STW的。处理一些边缘情况,比如弱引用,这个阶段很快,时间较短

标记过程中,除了使用“Colored Pointer”进行标记外,针对每一个page还会使用liveMap记录page里哪些对象时活得,以及所占空间,为下一个阶段中 选择合适回收page和存活对象重定位做准备。

指针表示一个字节在虚拟内存中的具体地址,我们42位表示指针的地址,4位来表示这个指针的一些属性(Finalizable,Remapped,Marked,Marked)用于ZGC标记

  • Finalizable标记只能通过终结器访问对象
  • Remapped 表示这个引用是最新的,只想对象的当前位置。在load-barrier中,完成重映射后,会设置为Remapped
  • Marked0和Marked1 标记可访问的对象,在ZGC标记过程中,使用这两交替访问

ZGC使用42位表示地址,所以ZGC支持堆内存最大位4TB,JDK15中,扩展到了16T

5. 重定位过程

在完成了标记对象标记后,需要进行具体的回收工作了,在ZGC中,使用复制算法来进行垃圾回收。重定位过程会把需要垃圾回收的page中存活的对象移到一个新的page中,page中存活对象移动完成后,page的回收就完成了。

重定位包含以下阶段:

  • 准备重定位,这个过程是并发的,主要是选择想进行回收的page,放入到重定位集中。

  • 开始重定位,这个过程是stw的,将relocation set中所有根引用重定位,并且更新引用

  • 重定位是并发的,根据标记得到的liveMap,GC线程对relocation set中所有存活的对象进行重定位,将新旧地址之间的映射存储在转发表中,应用线程在访问到GC线程还没来得及重定位的对象时,也会给对象进行重定位

6. 重映射过程

重定位只是在转发表中保存了新旧地址的映射,并没有对对象的引用进行更新

当访问对象时,使用的引用地址还是错误的地址,在ZGC中,在Load-Barrier中,根据引用的状态和转发表中的记录,进行引用地址的修正,确保每次能访问到正确对象,并将对象设置为Remapped

ZGC将这个指针修正的过程被称为指针的自愈

其余没有被Load-Barrier,将在下一个标记阶段进行

因为在引用修正的过程中,放在了Load-Barrier中,由应用线程处理,所以,在一次GC中,我们只需要在标记过程中遍历一次对象树。

7. Load-Barrier

Load Barrier可以翻译成读屏障,即写屏障。ZGC中,标记和移动阶段,每次【从堆里对象的引用类型中读取一个指针】的时候,都会触发一个Load-Barrier。(比如obj.fieldA)

8. 并发标记过程详解

并发标记时,GC线程和应用线程同时工作,需要特殊处理,防止出现漏标和错标的i情况。错标会出现浮动垃圾,影响不大,会在下一次垃圾回收中回收掉。漏标会让一些可达对象被当作垃圾处理,影响程序正确性,使用 Load-Barrier避免漏标

9. 如何进行页面回收的选择

选择分为两步:筛选可以被回收的页面,从中选择垃圾比较多的页面加入relocation set

  1. 筛选所有可以被回收的页面

    如果页面时本次垃圾回收启动后新分配的页面,就无需回收

    如果页面在标记过程中没标记过,即没有存活对象,可以直接放回页面缓存,重用。

    如果页面是大页面,则不回收,因为大页面只有一个对象,不能回收

    如果页面是中页面、或者小页面,则只有页面垃圾所占空间超过页面空间的25%时,才可以被回收

  2. 选择垃圾比较多的页面加入relocation set

    排序,根据页面的liveMap来计算活跃内存的大小,按照页面活跃内存数从小到大排序

    选择排序靠前的页面,加入relocation set

10. 总结

​ ZGC是一款以低延迟为首要目标,基于page内存布局的、不设分代的、使用了Load-Barrier、Colored Poiner和内存多视图映射等技术的并发垃圾收集器。stw时间只与根节点的数目有关,其余标记和处理过程都是并发的,因此可以保证时延时间基本不随着堆大小变化。但是部分标记和重映射工作由Load-Barrier来完成,吞吐量有所下降