ZGC垃圾收集器介绍

ZGC(The Z Garbage Collector)是JDK 11中推出的一款低延迟垃圾回收器,它的设计目标包括:

  • 停顿时间不超过10ms;
  • 停顿时间不会随着堆的大小,或者活跃对象的大小而增加;
  • 支持8MB~4TB级别的堆(未来支持16TB)

ZGC的目标是希望在尽可能对吞吐量影响不太大的前提下 ,实现在任意堆内存大小下都可以把垃圾收集的停顿时间限制在十毫秒以内的低延迟。

在ZGC算法中,并没有分代的概念,所以就不存在Young GC、Old GC,所有的GC行为都是Full GC

Region布局

先从ZGC的内存布局说起。

和G1一样,ZGC也采用基于Region的堆内存布局,但与G1不同的是,ZGC的Region具有动态性——动态创建和销毁,以及动态的区域容量大小。

在x64硬件平台下,ZGC的Region可以有小、中、大、三类容量:

  • 小型Region(Small Region):容量固定为2MB,用于放置小于256KB的小对象。
  • 中型Region(Medium Region):容量固定为32MB,用于放置大于等于256KB但小于4MB的对象。
  • 大型Region(Large Region):容量不固定,可以动态变化,但必须为2MB的整数倍,用于放置4MB或以上的大对象。每个大型Region中只会存放一个大对象,这也预示着虽然名字叫作「大型Region」,但它的实际容量完全有可能小于中型Region,最小容量可低至4MB。大型Region在ZGC的实现中是不会被重分配的,因为复制一个大对象的代价非常高昂。

读屏障

之前的GC都是采用写屏障(Write Barrier),而ZGC采用的是读屏障。

读屏障(Load Barriers)类似于 Spring AOP 的前置通知。

在ZGC中,当读取处于重分配集的对象时,会被读屏障拦截,通过转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象,ZGC将这种行为叫做指针的「自愈能力」。

这样就算GC把对象移动了,读屏障也会发现并修正指针,于是应用代码就永远都会持有更新后的有效指针,而且不需要STW,类似JDK里的CAS自旋,读取的值发现已经失效了,需要重新读取。

好处是:第一次访问旧对象访问会变慢,但也只会有一次变慢,当「自愈」完成后,后续访问就不会变慢了。

正是因为Load Barriers的存在,所以会导致配置ZGC的应用的吞吐量会变低。不过这点开销是值得的。

染色指针

ZGC收集器有一个标志性的设计是它采用的「染色指针」技术,是ZGC的核心设计之一。

以前的垃圾回收器的GC信息都保存在对象头中,而ZGC的GC信息保存在指针中。

ZGC 出现之前, GC 信息保存在对象头的 Mark Word 中,如对象的哈希码、分代年龄、锁记录等就是这样存储的。

追踪式收集算法的标记阶段就可能存在只跟指针打交道而不必涉及指针所引用的对象本身的场景。

例如对象标记的过程中需要给对象打上三色标记,这些标记本质上就只和对象的引用有关,而与对象本身无关。

而ZGC的染色指针将这些信息直接标记在引用对象的指针上。

染色指针是一种直接将少量额外的信息存储在指针上的技术,Linux下64位指针的高18位不能用来寻址,ZGC的染色指针技术盯上了这剩下的46位指针宽度,将其高4位提取出来存储四个标志信息

当然,由于这些标志位进一步压缩了原本就只有46位的地址空间,也直接导致ZGC能够管理的内存不可以超过4TB(2的42次幂)

JVM 可以从指针上直接看到对象的三色标记状态(Marked0、Marked1)、是否进入了重分配集(Remapped)、是否需要通过 finalize 方法来访问到(Finalizable)。

18位:预留给以后使用;
1位:Finalizable标识,此位与并发引用处理有关,它表示这个对象只能通过finalizer才能访问;
1位:Remapped标识,设置此位的值后,对象未指向relocation set中(relocation set表示需要GC的Region集合);
1位:Marked1标识;
1位:Marked0标识,和上面的Marked1都是标记对象用于辅助GC;
42位:对象的地址(所以它可以支持2^42=4T内存);

染色指针的优势

染色指针主要有三大优势:

  • 染色指针可以使得一旦某个Region的存活对象被移走之后,这个Region立即就能够被释放和重用掉,而不必等待整个堆中所有指向该Region的引用都被修正后才能清理。理论上只要还有一个空闲Region,ZGC就能完成收集。
  • 染色指针可以大幅减少在垃圾收集过程中内存屏障的使用数量,ZGC只使用了读屏障。因为信息直接维护在指针中。
  • 染色指针可以作为一种可扩展的存储结构用来记录更多与对象标记、重定位过程相关的数据,以便日后进一步提高性能
    如果开发了前18位指针,既可以腾出已用的4个标志位,将ZGC可支持的最大堆内存从4TB拓展到64TB,也可以利用其余位置再存储更多的标志,譬如存储一些追踪信息来让垃圾收集器在移动对象时能将低频次使用的对象移动到不常访问的内存区域。

运作过程

ZGC的运作过程大致可划分为以下四个大的阶段。全部四个阶段都是可以并发执行的,仅是两个阶段中间会存在短暂的停顿小阶段,这些小阶段,譬如初始化GC Root直接关联对象的Mark Start,ZGC的运作过程具体如图所示。

  • 并发标记(Concurrent Mark):并发标记是遍历对象图做可达性分析的阶段。与G1、Shenandoah不同的是,ZGC的标记是在指针上而不是在对象上进行的,标记阶段会更新染色指针中的Marked 0、Marked 1标志位

  • 并发预备重分配(Concurrent Prepare for Relocate):这个阶段需要根据特定的查询条件统计得出本次收集过程要清理哪些Region,将这些Region组成重分配集(Relocation Set)。

    重分配集与G1收集器的回收集(Collection Set)还是有区别的,ZGC划分Region的目的并非为了像G1那样做收益优先的增量回收。

    相反,ZGC每次回收都会扫描所有的Region,用范围更大的扫描成本换取省去G1中记忆集的维护成本

    因此,ZGC的重分配集只是决定了里面的存活对象会被重新复制到其他的Region中,里面的Region会被释放,而并不能说回收行为就只是针对这个集合里面的Region进行,因为标记过程是针对全堆的。

    此外,在JDK 12的ZGC中开始支持的类卸载以及弱引用的处理,也是在这个阶段中完成的。

  • 并发重分配(Concurrent Relocate):重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象到新对象的转向关系

    得益于染色指针的支持,ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配集之中,如果用户线程此时并发访问了位于重分配集中的对象,这次访问将会被预置的内存屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象。

    ZGC将这种行为称为指针的「自愈”(Self-Healing)」能力。这样做的好处是只有第一次访问旧对象会陷入转发,也就是只慢一次,对比Shenandoah的Brooks转发指针,那是每次对象访问都必须付出的固定开销,简单地说就是每次都慢。

    因此ZGC对用户程序的运行时负载要比Shenandoah来得更低一些。

    还有另外一个直接的好处是由于染色指针的存在,一旦重分配集中某个Region的存活对象都复制完毕后,这个Region就可以立即释放用于新对象的分配(但是转发表还得留着不能释放掉),哪怕堆中还有很多指向这个对象的未更新指针也没有关系,这些旧指针一旦被使用,它们都是可以自愈的。

  • 并发重映射(Concurrent Remap):重映射所做的就是修正整个堆中指向重分配集中旧对象的所有引用。

    这一点从目标角度看是与Shenandoah并发引用更新阶段一样的,但是ZGC的并发重映射并不是一个必须要「迫切」去完成的任务,因为前面说过,即使是旧引用,它也是可以自愈的,最多只是第一次使用时多一次转发和修正操作。

    重映射清理这些旧引用的主要目的是为了不变慢(还有清理结束后可以释放转发表这样的附带收益),所以说这并不是很「迫切」。因此,ZGC很巧妙地把并发重映射阶段要做的工作,合并到了下一次垃圾收集循环中的并发标记阶段里去完成,反正它们都是要遍历所有对象的,这样合并就节省了一次遍历对象图的开销。一旦所有指针都被修正之后,原来记录新旧对象关系的转发表就可以释放掉了。

ZGC几乎整个收集过程都全程可并发,短暂停顿也只与GC Roots大小相关而与堆内存大小无关,因而同样实现了任何堆上停顿都小于十毫秒的目标。

总结:

相比G1、Shenandoah等先进的垃圾收集器,ZGC在实现细节上做了一些不同的权衡选择。

譬如G1需要通过写屏障来维护记忆集,才能处理跨代指针,得以实现Region的增量回收。记忆集要占用大量的内存空间,写屏障也对正常程序运行造成额外负担,这些都是权衡选择的代价。

ZGC就完全没有使用记忆集,它甚至连分代都没有,连像CMS中那样只记录新生代和老年代间引用的卡表也不需要,因而完全没有用到写屏障,所以给用户线程带来的运行负担也要小得多。

可是,有优就有劣,ZGC的这种选择也限制了它能承受的对象分配速率不会太高。

因为ZGC四个阶段都支持并发,如果分配速率高,将创造大量的新对象,这就产生了大量的浮动垃圾。如果这种高速分配持续维持的话,回收到的内存空间持续小于期间并发产生的浮动垃圾所占的空间,堆中剩余可腾挪的空间就越来越小了。

目前唯一的办法就是尽可能地增加堆容量大小,获得更多喘息的时间。但是若要从根本上提升ZGC能够应对的对象分配速率,还是需要引入分代收集,让新生对象都在一个专门的区域中创建。所以分代算法有利有弊。

最后对本篇文章做一个提炼总结:

ZGC(Z Garbage Collector)是一个面向并行、无停顿时间的垃圾回收器,它作为JDK11的一部分首次引入,并且在JDK15开始被正式视为生产就绪级别:

  1. 出现意义:面对现代硬件环境中大内存、多核心的趋势以及微服务等新型应用的需求,如低延迟和高吞吐量,传统的垃圾收集器(如Parallel GC和CMS等)可能无法满足要求,尤其在处理多达数TB内存的情况下。在这样的背景下,ZGC应运而生,其设计目标是处理大型堆内存,同时将停顿时间限制在10ms以内,并且不牺牲整体吞吐量。
  2. 主要特点:其采用读屏障(Read Barrier)和染色指针(Colored Pointer)技术,实现了可扩展性,可以从几百MB到4TB的Java堆大小进行高效处理。此外,ZGC能够实现几乎所有的工作都在并行和并发阶段完成,包括对象可达性的标记、对象重定位和引用更新等操作。这使得它能够大幅度地降低垃圾收集带来的停顿时间。
  3. 适用场景:ZGC非常适合需要大内存,低延时,以及可预测的响应时间的系统,例如,金融交易、游戏、广告科技等领域的应用。
  4. 局限性:尽管ZGC有许多优点,但也有一些局限性。例如,由于其复杂的实现,对JVM的代码入侵较深,可能会与一些JVM特性或者优化手段不兼容。另外,尽管ZGC的暂停时间很短,但并发处理可能占用较多的CPU资源,所以在CPU敏感的环境下,其表现可能不如其他垃圾收集器。

总的来说,ZGC是一种创新的垃圾收集器,它解决了大内存和低延迟之间的矛盾,为构建现代大规模、高性能的Java应用提供了更多可能。

通过美团分享的文章,zgc也有适用和非适用的场景,

在Zeus服务不同集群中,ZGC在低延迟(TP999 < 200ms)场景中收益较大:

  • TP999:下降12~142ms,下降幅度18%~74%。
  • TP99:下降5~28ms,下降幅度10%~47%。

超低延迟(TP999 < 20ms)和高延迟(TP999 > 200ms)服务收益不大,原因是这些服务的响应时间瓶颈不是GC,而是外部依赖的性能,对吞吐量优先的场景,ZGC可能并不适合。例如,Zeus某离线集群原先使用CMS,升级ZGC后,系统吞吐量明显降低。究其原因有二:第一,ZGC是单代垃圾回收器,而CMS是分代垃圾回收器。单代垃圾回收器每次处理的对象更多,更耗费CPU资源;第二,ZGC使用读屏障,读屏障操作需耗费额外的计算资源。

所以可以参考自己的业务,是否适合升级

知乎也有一些线上fgc问题的排查过程

java fgc - 搜索结果 - 知乎

参考:

新一代垃圾回收器ZGC的探索与实践 - 美团技术团队

 https://www.cnblogs.com/booksea/p/17665685.html

Java ZGC垃圾收集器(算法及回收原理详解) – mikechen

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/239105.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙开发工具DevEco Studio的安装与使用

鸿蒙开发工具的安装与使用 1、下载 根据自己的电脑下载对应版本的IED&#xff1a;官网&#xff1a;HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 下载后进行安装安装路径不要有中文&#xff0c;空格&#xff0c;特殊符号 下载之后得到的是一个压缩文件&#xff0…

如何在企业微信开发者中心使用内网穿透工具回调本地接口服务

文章目录 1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 企业微信开发者在应用的开发测试阶段&#xff0c;应用服务通常是部署在开发环境&#xff0c;在有数据回调的开发场…

四、Sharding-JDBC系列04:分库分表后,如何不停机迁移数据?

目录 停机迁移方案 双写迁移方案 一般会有两种方案&#xff1a; 停机迁移方案 这种方案最简单也是最low的。 数据迁移前&#xff0c;在网站或者app挂个公告&#xff0c;说0点到早上6点系统进行维护&#xff0c;无法访问。 接着到0点停机&#xff0c;系统停掉&#xff0c;…

如何检查Post body并作出响应?

如果需要针对POST body中包含的参数对传入的请求作出响应&#xff0c;你打算怎么做&#xff1f;其实在使用Akamai EdgeWorkers的情况下&#xff0c;只需要一些高级MD&#xff08;MetaData&#xff09;技巧&#xff0c;这一切实现起来可以变得非常简单。 Akamai EdgeWorkers是什…

东北编程语言???

在GitHub闲逛&#xff0c;偶然发现了东北编程语言&#xff1a; 东北编程语言是由Zhanyong Wan创造的&#xff0c;它使用东北方言词汇作为基本关键字。这种编程语言的特点是简单易懂&#xff0c;适合小学文化程度的人学习&#xff0c;并且易于阅读、编写和记忆。它的语法与其他编…

IO网络2.0

思维导图 机械臂 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <myhead.h> #define SER_PORT 8888 #define SER_IP "192.168.122.68" //服务端//TCP客户端 int main(int argc, const char *argv[]) {//创建套接字…

在 Nvidia Docker 容器编译构建显存优化加速组件 xFormers

本篇文章&#xff0c;聊聊如何在新版本 PyTorch 和 CUDA 容器环境中完成 xFormers 的编译构建。 让你的模型应用能够跑的更快。 写在前面 xFormers 是 FaceBook Research &#xff08;Meta&#xff09;开源的使用率非常高的 Transformers 加速选型&#xff0c;当我们使用大模…

十大必备功能:打造高效知识库的关键因素

一个好的产品知识库应该成为客户了解产品功能、解决故障和满足产品相关查询的重要资源。但如果没有合理地维护和更新&#xff0c;其可能就失去了存在的价值。 知识库的有效性取决于其包含的信息是否全面、准确和实用。而要实现这一点&#xff0c;需要关注一些关键功能。 以人…

Docker安全基线检查需要修复的一些问题

一、可能出现的漏洞 限制容器之间的网络流量 限制容器的内存使用量 为Docker启用内容信任 将容器的根文件系统挂载为只读 审核Docker文件和目录 默认情况下&#xff0c;同一主机上的容器之间允许所有网络通信。 如果不需要&#xff0c;请限制所有容器间的通信。 将需要相互通…

在服务器上使用Docker运行SRS Stack,推拉直播流、多平台转播、本地录制、虚拟直播、直播转码、AI字幕、其他

SRS Stack | SRS (ossrs.net) Docker​ 推荐使用Docker运行SRS Stack&#xff1a; docker run --restart always -d -it --name srs-stack -v $HOME/data:/data \-p 2022:2022 -p 2443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \registry.cn-hangzhou.aliyun…

深度学习论文解读分享之diffGrad:一种卷积神经网络优化方法

IEEE TNNLS 2020&#xff1a;diffGrad: 一种卷积神经网络优化方法 题目 diffGrad: An Optimization Method for Convolutional Neural Networks 作者 Shiv Ram Dubey , Member, IEEE, Soumendu Chakraborty , Swalpa Kumar Roy , Student Member, IEEE, Snehasis Mukherjee…

K8S----YAML

kubernetes中资源可以使用YAML描述&#xff08;如果您对YAML格式不了解&#xff0c;可以参考YAML语法&#xff09;&#xff0c;也可以使用JSON。其内容可以分为如下四个部分&#xff1a; typeMeta&#xff1a;对象类型的元信息&#xff0c;声明对象使用哪个API版本&#xff0c…

井盖异动传感器,守护脚下安全

随着城市化进程的加速&#xff0c;城市基础设施的安全问题日益受到关注。其中&#xff0c;井盖作为城市地下管道的重要入口&#xff0c;其安全问题不容忽视。然而&#xff0c;传统的井盖监控方式往往存在盲区&#xff0c;无法及时发现井盖的异常移动。为此&#xff0c;我们推出…

nginx查看连接数的几种方法

前言 nginx作为目前最流行的web服务器之一&#xff0c;在许多生产环境都能看到他的踪影。有时候&#xff0c;我们需要统计nginx的连接配置&#xff0c;本文主要分享一下如何统计nginx的连接数。 方法一 netstat 使用netstat统计连接数&#xff0c;这种是将master和worker一起…

linux安装MySQL5.7(安装、开机自启、定时备份)

一、安装步骤 我喜欢安装在/usr/local/mysql目录下 #切换目录 cd /usr/local/ #下载文件 wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz #解压文件 tar -zxvf mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz -C /usr/local …

使用Cloudreve快速搭建一个私有网盘,配置存储策略和管理权限以及Webdav设置访问

Cloudreve 是什么&#xff1f; Cloudreve 可以让您快速搭建起公私兼备的网盘系统。Cloudreve 在底层支持不同的云存储平台&#xff0c;用户在实际使用时无须关心物理存储方式。你可以使用 Cloudreve 搭建个人用网盘、文件分享系统&#xff0c;亦或是针对大小团体的公有云系统。…

LogicBroker上进行 Babylist EDI项目测试指南

在LogicBroker上启动对接Babylist onboarding流程 接受邀请并填写Onboarding表单 企业将会收到一封入驻邀请电子邮件&#xff0c;邮件中将会包含Onboarding表单的链接。 1.在标题为 “[Supplier] has been invited to connect with [Retailer]” 的邮件中&#xff0c;点击Ac…

GIT SourceTree 回滚提交

步骤一&#xff1a; 步骤二&#xff1a; 步骤三&#xff1a; 在终端输入命令&#xff08;位置是项目目录下&#xff09; git push origin feature_mo2.1_r3_zhanx653 -f

Git的简单使用说明

Git入门教程 git的最主要的作用&#xff1a;版本控制&#xff0c;协助开发 一.版本控制分类 ​​ 1.本地版本控制 ​​ 2.集中版本控制 ​​ 所有的版本数据都存在服务器上&#xff0c;用户的本地只有自己以前所同步的版本&#xff0c;如果不连网的话&#xff0c;用户就看不…

解决ssh:connect to host github.com port 22: Connection timed out与kex_exchange_identification

一、问题 无法进行clone项目和其他Git操作。执行检测连接命令 ssh -T gitgithub,com报错 ssh:connect to host github.com port 22: Connection timed out 即&#xff1a;连接22端口超时 涉及到的文件&#xff1a; C:\Users\JIACHENGER.ssh\config C:\Users\JIACHENGER.ssh\…