Java11 高效垃圾回收器-ZGC

一:ZGC介绍

ZGC 是最新的 JDK1.11 版本中提供的高效垃圾回收算法,ZGC 针对大堆内存设计可以支持 TB 级别的堆,ZGC 非常高效,能够做到 10ms 以下的回收停顿时间。

ZGC实现的依赖技术:

  1. 着色指针
    Java11 高效垃圾回收器-ZGC_第1张图片
    着色指针是一种将信息存储在指针(或使用Java术语引用)中的技术。因为在64位平台上(ZGC仅支持64位平台),指针可以处理更多的内存,因此可以使用一些位来存储状态。 ZGC将限制最大支持4Tb堆(42-bits),那么会剩下22位可用,它目前使用了4位: finalizable, remap, mark0和mark1。
  • inalizable 位:仅 finalizer(类比 c++ 中的析构函数)可访问;
  • remap 位:指向对象当前(最新)的内存地址,参考下面提到的 relocation;
  • marked0 && marked1 位:用于标志可达对象;
    这 4 个标志位,同一时刻只会有 1 个位置是 1。每当指针对应的内存数据发生变化,比如内存被移动,颜色会发生变化。
  1. 读屏障
    传统 GC 做标记时,为了防止其它线程在标记期间修改对象,通常会简单的 STW。而 ZGC 有了 Colored Pointer 后,引入了所谓的读屏障,当指针引用的内存正被移动时,指针上的颜色就会变化,ZGC 会先把指针更新成最新状态,然后再返回。(大家可以回想下 java 中的 volatile 关键字,有异曲同工之妙),这样仅读取该指针时可能会略有开销,而不用将整个 heap STW。
  2. 动态调整大小的 Region
    虽然也利用了Region的概念,但是没有进行分代。G1 中每个 Region 需要借助额外的 Remembered Set 来记录“谁引用了我”,占用了额外的内存空间,每次对象移动时,RSets 也需要更新,会产生开销。而且ZGC 的 Region 不像 G1 那样是固定大小,而是动态地决定 Region 的大小,Region 可以动态创建和销毁。这样可以更好的对大对象进行分配管理。
  3. 重定位
    Java11 高效垃圾回收器-ZGC_第2张图片
    如上图,在标记过程中,先从 Roots 对象找到了直接关联的下级对象 1,2,4。
    Java11 高效垃圾回收器-ZGC_第3张图片
    然后继续向下层标记,找到了 5,8 对象, 此时已经可以判定 3,6,7 为垃圾对象。
    Java11 高效垃圾回收器-ZGC_第4张图片
    如果按常规思路,一般会将 8 从最右侧的 Region 移动或复制到中间的 Region,然后再将中间 Region 的 3 干掉,最后再对中间 Region 做压缩 compact 整理。但 ZGC 做得更高明,它直接将 4,5 复制到了一个空的新 Region 就完事了,然后中间的 2 个 Region 直接废弃,或理解为“释放”,做为下次回收的“新”Region。这样的好处是避免了中间 Region 的 compact 整理过程。
    Java11 高效垃圾回收器-ZGC_第5张图片
    最后,指针重新调整为正确的指向(即:remap),而且上一阶段的 remap 与下一阶段的 mark 是混在一起处理的,相对更高效。

二:ZGC 回收过程

Java11 高效垃圾回收器-ZGC_第6张图片
开始进行回收时,ZGC 首先会进行一个短暂的 STW,来进行 roots 标记。这个步骤非常短,因为 roots 的总数通常比较小。

然后就开始进行并发标记,如上图所示,通过对对象指针进行着色来进行标记,结合读屏障解决单个对象的并发问题。其实,这个阶段在最后还是会有一个非常短的 STW 停顿,用来处理一些边缘情况,这个阶段绝大部分时间是并发进行的,所以没有明显标出这个停顿。

下一个是清理阶段,这个阶段会把标记为不在使用的对象进行回收,如上图所示,把橘色的不在使用的对象进行了回收。

最后一个阶段是重定位,重定位就是对 GC 后存活的对象进行移动,来释放大块的内存空间,解决碎片问题。

重定位最开始会有一个短暂的 STW,用来重定位集合中的 root 对象。暂停时间取决于 root 的数量、重定位集与对象的总活动集的比率。

最后是并发重定位,这个过程也是通过读屏障,与应用线程并发进行的。

你可能感兴趣的:(Java)