您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
垃圾回收器-ZGC的设计思路
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
垃圾回收器-ZGC的设计思路
自猿其说Tech
2021-08-26
IP归属:未知
34960浏览
计算机编程
### 1 ZGC介绍 ZGC收集器(Z Garbage Collector)是由Oracle公司研发的。2018年创建了JEP 333将ZGC提交给OpenJDK,推动其进入OpenJDK11的发布清单中,zgc是一款可拓展的低时延,为实现以下几个目标而诞生的垃回收器: - 停顿时间不超过10ms - 停顿时间不会导致堆大小增长 - 堆大小范围可支持几G到几T **zgc的标签:** - 与Shenandoah和G1一样,ZGC也采用基于Region的堆内存布局。 - ZGC的Region具有动态性。 - 动态创建和销毁 - 动态的区域容量大小 ### 2 ZGC原理 与CMS中的ParNew和G1类似,ZGC也采用标记-复制算法,不过ZGC对该算法做了重大改进:ZGC在标记、转移和重定位阶段几乎都是并发的,这是ZGC实现停顿时间小于10ms目标的最关键原因。 ZGC垃圾回收周期如下图所示: ![](//img1.jcloudcs.com/developer.jdcloud.com/1ee043a4-13d1-4de2-a8ff-09a48d9259fc20210826134535.png) ZGC只有三个STW阶段:初始标记,再标记,初始转移。其中,初始标记和初始转移分别都只需要扫描所有GC Roots,其处理时间和GC Roots的数量成正比,一般情况耗时非常短;再标记阶段STW时间很短,最多1ms,超过1ms则再次进入并发标记阶段。即,ZGC几乎所有暂停都只依赖于GC Roots集合大小,停顿时间不会随着堆的大小或者活跃对象的大小而增加。与ZGC对比,G1的转移阶段完全STW的,且停顿时间随存活对象的大小增加而增加。 ### 3 染色指针 在讲ZGC并发处理算法之前,还需要补充一个知识点——染色指针。 我们都知道,之前的垃圾收集器都是把GC信息(标记信息、GC分代年龄..)存在对象头的Mark Word里。举个例子: 如果某个人是个垃圾人,就在这个人的头上盖一个“垃圾”的章;如果这个人不是垃圾了,就把这个人头上的“垃圾”印章洗掉。 **而ZGC是这样做的:** 如果某个人是垃圾人。就在这个人的身份证信息里面标注这个人是个垃圾,以后不管这个人在哪刷身份证,别人都知道他是个垃圾人了。也许哪一天,这个人醒悟了不再是垃圾人了,就把这个人身份证里面的“垃圾”标志去掉。 在这例子中,“这个人”就是一个对象,而“身份证”就是指向这个对象的指针。 ZGC将信息存储在指针中,这种技术有一个高大上的名字——染色指针(Colored Pointer)。 ![](//img1.jcloudcs.com/developer.jdcloud.com/c7232b85-797c-42ec-bfd4-110ab64da42420210826134630.png) **在64位的机器中,对象指针是64位的。** - ZGC使用64位地址空间的第0~43位存储对象地址,2^44 = 16TB,所以ZGC最大支持16TB的堆。 - 而第44~47位作为颜色标志位,Marked0、Marked1和Remapped代表三个视图标志位,Finalizable表示这个对象只能通过finalizer才能访问。 - 第48~63位固定为0没有利用。 ### 4 读屏障 读屏障是JVM向应用代码插入一小段代码的技术。当应用线程从堆中读取对象引用时,就会执行这段代码。千万不要把这个读屏障和Java内存模型里面的读屏障搞混了,两者根本不是同一个东西,ZGC中的读屏障更像是一种AOP技术,在字节码层面或者编译代码层面给读操作增加一个额外的处理。 #### 4.1 读屏障实例 ```java Object o = obj.FieldA // 从堆中读取对象引用,需要加入读屏障 <load barrier needed here> Object p = o // 无需加入读屏障,因为不是从堆中读取引用 o.dosomething() // 无需加入读屏障,因为不是从堆中读取引用 int i = obj.FieldB // 无需加入读屏障,因为不是对象引用 ``` #### 障的4.2 ZGC中读屏障的代码作用 GC线程和应用线程是并发执行的,所以存在应用线程去A对象内部的引用所指向的对象B的时候,这个对象B正在被GC线程移动或者其他操作,加上读屏障之后,应用线程会去探测对象B是否被GC线程操作,然后等操作完成再读取对象,确保数据的准确性。具体的探测和操作步骤如下: ![](//img1.jcloudcs.com/developer.jdcloud.com/1659ab8a-0aa8-41e4-b5fe-e885b35070ed20210826134741.png) 这样会影响程序的性能吗? **会。**据测试,最多百分之4的性能损耗。但这是ZGC并发转移的基础,为了降低STW,设计者认为这点牺牲是可接受的。 ### 5 ZGC的优点 - 低停顿,高吞吐量,ZGC收集过程中额外耗费的内存小。 - 低停顿,几乎所有过程都是并发的,只有短暂的STW。 - 内存小,ZGC没有写屏障,卡表之类的。 - 吞吐量方面,在ZGC的‘弱项’吞吐量方面,因为和用户线程并发,还是有影响的。但是!但是!,以低延迟为首要目标的ZGC已经达到了以高吞吐量为目标Parallel Scavenge的99%,直接超越了G1。 - G1通过写屏障维护记忆集,才能处理跨代指针,得以实现增量回收。记忆集占用大量内存,写屏障对正常程序造成额外负担。 - 在多核处理器的某种架构下,ZGC优先在线程当前所处的处理器的本地内存上分配对象,以保证内存高效访问。 - 并发停顿方面:ZGC只有短暂的STW,大部分的过程都是和应用线程并发执行,比如最耗时的并发标记和并发移动过程。 - ZGC中没有引入分代,也就没有新生代和老年代的概念,只有一块一块的内存区域page,以page单位进行对象的分配和回收。 - 并发的标记-整理算法。没有内存碎片。 ### 6 ZGC的缺点 - 承受的对象分配速率不会太高,因为浮动垃圾。 - 停顿时间ZGC是在10ms以下,但是ZGC的执行时间还是远远大于这个时间的。假如ZGC全过程需要执行10分钟,在这个期间由于对象分配速率很高,将创建大量的新对象,这些对象很难进入当次GC,所以只能在下次GC的时候进行回收,这些只能等到下次GC才能回收的对象就是浮动垃圾。 - 造成回收到的内存空间小于期间并发产生的浮动垃圾所占的空间。 - ZGC没有分代概念,每次都需要进行全堆扫描,导致一些“朝生夕死”的对象没能及时的被回收。所以就不存在Young GC、Old GC,所有的GC行为都是Full GC。 ### 7 总结 ZGC确实是Java的最前沿的技术,但在G1都没有普及的今天,谈论ZGC似乎为时过早。但也许我们探讨的不是ZGC,而是ZGC背后的设计思路。 ------------ ###### 自猿其说Tech-JDL京东物流技术发展部 ###### 作者:北斗星团队(网规技术部 王新宇)
原创文章,需联系作者,授权转载
上一篇:京麦客户端插件质量体系设计与实践
下一篇:数据结构与算法之双指针
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号