哈喽,大家好,我是指北君。
本期指北君为大家分享 ZGC 垃圾回收器,它的诞生目标就极为诱人:
①、支持TB级堆内存(最大4T)
②、最大GC停顿10ms
③、对吞吐量影响最大不超过15%
ZGC 应该是后面Java项目会采用的主流垃圾回收器,也是 JDK17 默认的垃圾回收器,话不多说,本篇文章指北君为大家介绍:ZGC 原理是什么,以及它为什么能做到低延时?
作为一个长期从事电商工作的coder,大家知道电商交易讲究的准确、速度快。我们选取的主语言是Java,因为其生态实在是太强大了,但是Java的垃圾回收机制,会有 STW(Stop The World)产生,简单来说就是由于垃圾回收机制,会产生停顿现象。
众所周知,GC停顿对响应时间还是有很大的影响的,为了降低GC停顿对系统可用性的影响,我们从降低单次GC时间和降低GC频率两个角度出发进行了调优,包括JVM参数调优,以及更换垃圾回收器,从 CMS 到 G1垃圾回收器等等,但是效果都不太理想。
直到遇到了 ZGC。话不多说,直接开始吧!
1、官方介绍
为了保证介绍的足够官方,足够权威,我们先看看官方介绍:
核心理念:
- 停顿时间不超过10ms;
- 停顿时间不会随着堆的大小,或者活跃对象的大小而增加;
- 支持8MB~4TB级别的堆(未来支持16TB)。
这样响应了本文标题:ZGC 确实是低延时。
2、垃圾回收优化历程
为了降低 GC 延时,我们通常有这样几种解决思路:
①、缩短单次 GC 回收时间;
②、并发进行回收(CMS垃圾回收器,只能做到一部分并发);
③、只回收部分垃圾(G1垃圾回收器,打开新的大门);
④、ZGC(单独拿出来)
3、ZGC 原理
讲到这,开始正式进入主题:为什么 ZGC 能够做到低延时?
咱们看图说话:
低延时结论:
ZGC在标记、转移和重定位阶段几乎都是并发。
在【初始标记】、【再标记】、【初始转移】这三个阶段只有 GC 线程,这就表示这三个阶段是 STW 的。其中,初始标记和初始转移分别都只需要扫描所有GC Roots,其处理时间和GC Roots的数量成正比,一般情况耗时非常短;再标记阶段STW时间很短,最多1ms,超过1ms则再次进入并发标记阶段。即,ZGC几乎所有暂停都只依赖于GC Roots集合大小,停顿时间不会随着堆的大小或者活跃对象的大小而增加。
关键技术
ZGC通过着色指针和读屏障技术,解决了转移过程中准确访问对象的问题,实现了并发转移。
GC 线程在转移对象的过程中,假设不是 STW,这也是 G1 垃圾收集器慢的原因(G1这个阶段会 STW),那么应用线程也在不断的访问对象,假设对象转移,但对象地址没有及时更新,就会造成访问旧地址的错误。
在ZGC中,应用线程访问对象将触发“读屏障”,如果发现对象被移动了,那么“读屏障”会把读出来的指针更新到对象的新地址上,这样应用线程始终访问的都是对象的新地址。那么,JVM是如何判断对象被移动过呢?就是利用对象引用的地址,即着色指针。
关于“读屏障”和“着色指针”的概念,我这里就不做过多的描述了。
4、ZGC 缺点
ZGC 快是快,特别是对于大堆和即时响应的系统特别有用,但是还是存在缺点的:
①、并发标记阶段是全堆标记,如果回收速度跟不上对象分配速度,会导致对象分配停顿。
②、GC线程并发导致 CPU 飙高。
怎么用大家做好取舍。
5、小结
好了,这就是JDK中ZGC 的介绍,赶紧用起来吧。
我是指北君,操千曲而后晓声,观千剑而后识器。感谢各位人才的:点赞、收藏和评论,我们下期更精彩!