ZGC(Z Garbage Collector)完全指南

13,620 阅读6分钟

ZGC是从JDK11中引入的一种新的支持弹性伸缩低延迟垃圾收集器,ZGC可以工作在KB~TB的内存之下,作为一种并发的垃圾收集器,ZGC保证应用延迟不会超过10毫秒(即便在堆内存很大的情况下),在JDK11中是以实验阶段的特性被发布出来的,到JDK13时,ZGC可以支持到16TB的堆内存,并且可以将未提交的内存归还给操作系统

为什么引入ZGC

JVM的自动垃圾收集虽然减少了开发人员的工作,在一定程度上减少了内存泄漏的风险,但是由于GC是自动进行的,一些无法预知的事情有时候可能产生对应用有害的影响。

  • 延迟增加导致应用的吞吐量和性能

随着时代发展,硬件会逐渐便宜,应用使用的内存将会越来越大,但是又不能增加延迟,降低吞吐量

ZGC保证,不管在什么情况下,延迟不会超过10毫秒。

The Z Garbage Collector, also known as ZGC, is a scalable low latency garbage collector designed to meet the following goals:

  • Pause times do not exceed 10ms
  • Pause times do not increase with the heap or live-set size
  • Handle heaps ranging from a few hundred megabytes to multi terabytes in size

ZGC特性

ZGC最典型的特性是它是一款并发(concurrent)的GC,其它的特性如下:

  • 它可以标记内存,复制和迁移(relocate)内存,所有的操作都是并发的,同时它有一个并发的引用处理器
  • 其它的垃圾收集器都是使用store barriers,ZGC使用load barriers,用于跟踪内存
    • lock->unlock->read->load 读内存
    • use->assign->store->write 写内存
  • ZGC可以更加灵活的配置大小和策略,相比于G1,它可以更好的处理非常大(very large)对象的释放
  • ZGC只有一代,没有新生代,老年代什么的,但是ZGC可以支持局部压缩,在内存恢复和迁移(reclaim and relocate)时,ZGC仍然有很高的性能
  • ZGC依赖NUMA-aware(非均衡存储器访问),需要我们的内存支持这种特点

特性进度表

  • JDK11,2018年 9月
    • ZGC发布
    • 不支持类的卸载。-XX:+ClassUnloading 不生效
  • JDK12 2019年 3月
    • 支持并发的类卸载
    • 暂停时间进一步缩短
  • JDK13 2019年 9月
    • 最大堆内存从4TB -> 16TB
    • 支持归还未使用的内存 uncommitting unused memory
    • 支持Linux与/AArch64平台
    • 减少时间到一个固定的时间点之下 (Reduced Time-To-Safepoint)
    • 支持 -XX:SoftMaxHeapSize ,当设置这个参数的时候,ZGC会尽量在指定的内存大小之下,除非为了避免内存溢出:参考:bugs.openjdk.java.net/browse/JDK-…
  • JDK 14 计划在2020年3月
    • 增加稳定性
    • 支持不连续的地址空间
    • ...

ZGC支持的平台:

平台 是否支持 当前进度
Linux/x64 Y Since JDK 11
Linux/AArch64 Y Since JDK 13
macOS In Progress
Windows In Progress

垃圾收集原理

几个术语:

  • parallel 多个垃圾收集线程在一起工作,应用可能会停止
  • serial 垃圾收集器只有一个线程在工作
  • stop the world 应用程序停止
  • concurrent 垃圾收集器在后台运行,应用程序同时也在运行
  • incremental 在垃圾收集工作结束之前,先停止垃圾收集,等一会再过来完成剩下的工作

ZGC引入了两个新的概念,pointer coloringload barriers.

Point Coloring

这个特性让ZGC能够发现,标记,定位和重新映射对象,它只能工作在64位的操作系统上,实现colored pointer需要虚拟地址(virtual address masking)。

image-20191107074011335

  • finalizable 对象可以被finalizer到达
  • marked0 和marked1 标记可达的对象
  • remap 引用指针到当前对象的地址,对象可能会被relocate,这个地址表示对象被relocate

Load Barrier

load barrier是一段代码,当线程从堆中加载引用的时候被运行。例如,当我们访问对象的一个非主要类型的属性。

在ZGC中,load barrier检查引用的元数据位,根据元数据位对引用的对象做一些处理,因此可能在我们获取对象的时候对象的引用会被修改掉,但是不影响我们的使用。

实战

可以从jdk官网下载最新版本的JDK,下载地址:

www.oracle.com/technetwork…

快速开始

GC日志标记格式如下:

-Xlog:<tag set>,[<tag set>, ...]:<log file>

只是想要查看ZGC是否生效:

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx<size> -Xlog:gc

想要查看更加详细的ZGC日志信息:

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx<size> -Xlog:gc*

将更详细的日志信息记录在文件中:

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx<size> -Xlog:gc*:gc.log

img

GC调参

通用GC选项 ZGC选项 ZGC 诊断选项-XX:+UnlockDiagnosticVMOptions
-XX:MinHeapSize, -Xms -XX:InitialHeapSize, -Xms -XX:MaxHeapSize, -Xmx -XX:SoftMaxHeapSize -XX:SoftRefLRUPolicyMSPerMB -XX:ZAllocationSpikeTolerance -XX:ZCollectionInterval -XX:ZFragmentationLimit -XX:ZMarkStackSpaceLimit -XX:ZPath -XX:ZUncommit -XX:ZUncommitDelay -XX:ZProactive -XX:ZStatisticsInterval -XX:ZVerifyForwarding -XX:ZVerifyMarking -XX:ZVerifyObjects -XX:ZVerifyRoots -XX:ZVerifyViews

是否启用NUMA支持:

# 启用NUMA
-XX:+UseNUMA 

# 停用NUMA
-XX:-UseNUMA 

调整并发的线程数:

-XX:ConcGCThreads=

返回未提交的内存到操作系统,堆内存不会地址设置的最小堆内存-Xms

# 多久未提交的内存会返回给系统
-XX:+ZUncommit  -XX:ZUncommitDelay=<seconds>

开启大分页,一般会带来更好的性能提升,吞吐量,延迟和启动时间都有所改善。并没有看到明显的缺点

  • 大分页在Linux系统中一般为2MB的大小,如果有16G的堆内存,那么意味着需要16GB/2MB = 8192个大分页,以下命令需要 Linux kernel >= 4.14
# 配置操作系统中的分页池数量
echo 9216 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# 查看系统中现在的分页数量
cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages


-XX:+UseLargePages
  • 如果Linux kernel < 4.14,那么如下方式
mkdir /hugepages
mount -t hugetlbfs -o uid=123 nodev /hugepages 
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms16G -Xmx16G -XX:+UseLargePages

开启透明分页,透明分页可能导致延迟上的一些问题,有时候不推荐使用,开启透明分页需要Linux kernel < 4.7

# 开启透明分页
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
echo advise > /sys/kernel/mm/transparent_hugepage/shmem_enabled


-XX:+UseTransparentHugePage

最后

ZGC仍然是处于试验特性阶段,但其保证延迟时间不低于10ms的特性,以及当前对堆内存大小的支持力度,还是值得一试,让我们期待ZGC成为一款更加优越的垃圾收集器吧。

参考