Java ZGC垃圾回收器,了解不?
优质文章,第一时间送达
一:ZGC介绍
ZGC 是最新的 JDK1.11 版本中提供的高效垃圾回收算法,ZGC 针对大堆内存设计可以支持 TB 级别的堆,ZGC 非常高效,能够做到 10ms 以下的回收停顿时间。
ZGC实现的依赖技术:
1、着色指针
着色指针是一种将信息存储在指针(或使用Java术语引用)中的技术。因为在64位平台上(ZGC仅支持64位平台),指针可以处理更多的内存,因此可以使用一些位来存储状态。ZGC将限制最大支持4Tb堆(42-bits),那么会剩下22位可用,它目前使用了4位:finalizable, remap, mark0和mark1。
inalizable 位:仅 finalizer(类比 c++ 中的析构函数)可访问;
marked0 && marked1 位:用于标志可达对象;
这 4 个标志位,同一时刻只会有 1 个位置是 1。每当指针对应的内存数据发生变化,比如内存被移动,颜色会发生变化。
2、读屏障
传统 GC 做标记时,为了防止其它线程在标记期间修改对象,通常会简单的 STW。而 ZGC 有了 Colored Pointer 后,引入了所谓的读屏障,当指针引用的内存正被移动时,指针上的颜色就会变化,ZGC 会先把指针更新成最新状态,然后再返回。(大家可以回想下 java 中的 volatile 关键字,有异曲同工之妙),这样仅读取该指针时可能会略有开销,而不用将整个 heap STW。
3、动态调整大小的 Region
虽然也利用了Region的概念,但是没有进行分代。G1 中每个 Region 需要借助额外的 Remembered Set 来记录“谁引用了我”,占用了额外的内存空间,每次对象移动时,RSets 也需要更新,会产生开销。而且ZGC 的 Region 不像 G1 那样是固定大小,而是动态地决定 Region 的大小,Region 可以动态创建和销毁。这样可以更好的对大对象进行分配管理。
4、重定位
如上图,在标记过程中,先从 Roots 对象找到了直接关联的下级对象 1,2,4。
然后继续向下层标记,找到了 5,8 对象, 此时已经可以判定 3,6,7 为垃圾对象。
如果按常规思路,一般会将 8 从最右侧的 Region 移动或复制到中间的 Region,然后再将中间 Region 的 3 干掉,最后再对中间 Region 做压缩 compact 整理。但 ZGC 做得更高明,它直接将 4,5 复制到了一个空的新 Region 就完事了,然后中间的 2 个 Region 直接废弃,或理解为“释放”,做为下次回收的“新”Region。这样的好处是避免了中间 Region 的 compact 整理过程。
最后,指针重新调整为正确的指向(即:remap),而且上一阶段的 remap 与下一阶段的 mark 是混在一起处理的,相对更高效。
二:ZGC 回收过程
开始进行回收时,ZGC 首先会进行一个短暂的 STW,来进行 roots 标记。这个步骤非常短,因为 roots 的总数通常比较小。
然后就开始进行并发标记,如上图所示,通过对对象指针进行着色来进行标记,结合读屏障解决单个对象的并发问题。其实,这个阶段在最后还是会有一个非常短的 STW 停顿,用来处理一些边缘情况,这个阶段绝大部分时间是并发进行的,所以没有明显标出这个停顿。
下一个是清理阶段,这个阶段会把标记为不在使用的对象进行回收,如上图所示,把橘色的不在使用的对象进行了回收。
最后一个阶段是重定位,重定位就是对 GC 后存活的对象进行移动,来释放大块的内存空间,解决碎片问题。
重定位最开始会有一个短暂的 STW,用来重定位集合中的 root 对象。暂停时间取决于 root 的数量、重定位集与对象的总活动集的比率。
最后是并发重定位,这个过程也是通过读屏障,与应用线程并发进行的。
————————————————
版权声明:本文为CSDN博主「tiger-guo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/qq_39833612/article/details/102807293
感谢点赞支持下哈