Java长期支持版本Java11发布时推出了ZGC, 之后的Java12 -16均有ZGC的一些更新。然而Java17的新特性已经敲定,确定没有关于ZGC的相关更新,也从另一方面说明了至Java17 ZGC已经比较稳定,可以作为比较稳定的GC垃圾回收器。相信未来ZGC必定会成为主流的Java垃圾回收期,那么盘一盘ZGC就是必然的了。
根据OpenJDK官方网站的说明ZGC其实并没有什么特殊意义,就是一个名字而已。起初只是为了致敬ZFS 文件系统,表示ZGC与ZFS一样都是革命性的,是一个跨时代的产品。更像是一种崇拜命名法。所以ZGC就是要做革命性的与以往的垃圾回收器性能上有很大提高的GC。
ZGC是一个低延迟的可扩展GC,它有以下的目标
同时ZGC有如下标签:
直至Java17 ZGC基本支持所有的主流系统。
尽管ZGC有比较大的改动,但是它仍然可以使用绝大部分的GC参数。当然它也有其特有的参数。
-XX:MinHeapSize, -Xms 最小堆大小 (default = 8388608 = 8M)
-XX:InitialHeapSize, -Xms 初始化堆大小 (default = 134217728 = 128M )
-XX:MaxHeapSize, -Xmx 最大堆大小 (default = 2134900736 = 2036M)
-XX:SoftMaxHeapSize JVM堆的最大软限制 (default = 2134900736 = 2036M)
-XX:ConcGCThreads 并发GC的线程数量(default -XX:+ConcGCThreads=1 )
-XX:ParallelGCThreads 设置垃圾回收时的并行GC线程数量 (default = 4 )
-XX:UseLargePages 使用大页面内存 (dafault false)
-XX:UseTransparentHugePages 使用Transparent大页面内存
-XX:UseNUMA 使用UNMA内存分配,可以获得更好的性能
-XX:SoftRefLRUPolicyMSPerMB 每MB的空闲内存空间允许软引用对象存活时间(default = 1000)
-XX:AllocateHeapAt = 堆分配参数,可以使用非DRAM 内存,这个参数将指向文件系统的文件并使用内存映射来达到在备用存储设备上进行堆分配。
-XX:ZAllocationSpikeTolerance 修正系数,数值越大,越早触发GC (default = 2.000000)
-XX:ZCollectionInterval ZGC发生的最小时间间隔 ,秒 (default = 0.000000)
-XX:ZFragmentationLimit relocation时,当前region碎片化大于此值,则回收region (default = 25.000000) -XX:ZMarkStackSpaceLimit 指定为标记堆栈分配的最大字节数 (default = 8589934592 = 8096M)
-XX:ZProactive 是否启用主动回收 (default true)
-XX:ZUncommit 是否归还不使用的内存给OS(default true)
-XX:ZUncommitDelay 不再使用的内存最多延迟多久会归还给OS (default = 300 s)
-XX:+UnlockDiagnosticVMOptions 使用诊断模式,下面的参数才会起作用
-XX:ZStatisticsInterval 指定统计数据输出之间的时间间隔(秒)。
-XX:ZVerifyForwarding 检验转发表 -XX:ZVerifyMarking 检验标记集
-XX:ZVerifyObjects 检验对象 -XX:ZVerifyRoots 检验根节点
-XX:ZVerifyViews 检验堆视图访问
-XX:+UseZGC 启用ZGC
-XX:+UseZGC -Xmx-Xlog:gc
-XX:+UseZGC -Xmx-Xlog:gc* 可以打印更详细的GC日志
ZGC比较重要的调优参数是设置最大堆内存(-Xmx<size>)., ZGC设置一个最大堆内存有两个考量:1.堆可以容纳程序的存活集 2.堆中要有足够的空间允许GC运行时分配.
然而多大内存合适这就要根据 内存使用情况以及GC频率来确定。
另一个调优参数就是并发GC线程数量的设置 (-XX:ConcGCThreads=<number>) 。
一般情况下ZGC可以自动选择一个合适的值,但是也要根据程序的特点来修改。这个参数对GC使用CPU的时间影响比较大,如果数量太大的话,GC线程会占用过多的CPU时间,数量过少的话垃圾回收有会不及时。通常情况下如果程序的低延迟很重要,那么CPU使用率最好永远不要超过70%。
默认情况下,ZGC会将不使用的内存还给OS。可以使用XX:-ZUncommit 取消这一功能。然而如果实际堆内存比最小堆内存都小的话,肯定不会将不使用的内存返还给OS,另外最大堆内存(-Xmx)和最小堆内存 (-Xms) 的设置相等的话,也不会起作用。
另外可以设置延迟归还对内存的时间 -XX:ZUncommitDelay=<seconds>
在Linux操作系统中,采用内存映射来管理内存,逻辑页面映射到对应的物理内存,
使用大页面这个参数在吞吐量,低延迟,启动时间方面都有很好的性能提升,可以说除了设置起来有点复杂之外,没有任何的缺点。设置这个参数需要Root权限,所以默认没有开启。
Linux下的大页分为两种标准,大页(Huge Pages)和透明大页(Transparent Huge Pages)。大页是预分配的方式管理,透明大页是动态分配的方式。我们可以使用这个参数-XX:+UseTransparentHugePages 来使用 transparent huge pages .对延迟要求很高的程序而言,这个参数是不推荐使用的,它可能会造成不必要的延迟峰值。
NUMA(非一致性内存访问)是Intel为了解决SMP多CPU结构中中线访问方式中资源竞争和一致性问题引起的。ZGC支持NUMA,此特性是默认开启的,它可以自主判断系统是否支持NUMA。如果在支持NUMA的机器上运行,那么将有显著的性能提升。
3.1 ZGC同G1类似,也将内存分为Regions, 叫做ZPages。ZPages可以动态的创建和销毁,而且还可以动态的变化大小,无论怎么变化均为2MB 的倍数。
ZGC的堆区可以分为Small(2MB) Medium(32MB) Large(N*2MB)等多个Heap Regions. 其中Medium和Large是连续分配的内存。
ZGC的垃圾回收一般可以分为已下几个步骤流程。
可以看出来ZGC整体使用了标记复制加整理的思想,不过ZGC可以根据当前的内存使用情况,选择将存活对象整理到一个全新的空Region集合中或者某个存有对象的Region中。由于整个GC的流程中只有三处需要暂停,然而这三处的STW时间都是亚毫秒级别。整个GC的流程延迟总体会小于1ms。
本片总体概括了介绍了比较成熟的ZGC,介绍了ZGC的一些重要调优参数,讲解了一下ZGC的垃圾回收流程。相信各位看官也有所收获。目前ZGC的应用比较少,但随着Java17的正式推出,那么ZGC必然会逐渐成为主流GC。后面指北君也会为大家进一步讲解ZGC的详细GC步骤。敬请期待!