zgc介绍
zgc在JDK15中终于官宣能够投入生产使用,官方博客的话就是稳定,高性能,低延时的gc。mysql
zgc的核心是一个并发垃圾回收器,其设计的目标是:算法
- 最大停顿时间是几毫秒
- 停顿时间不会随着堆变大而变大
- 堆范围8mb-16tb
固然zgc也有其余不少有用的功能例如:支持NUMA,支持NVRAM申请堆,类数据共享等等sql
本文主要讨论其在openjdk15和graalVM21和openjdk11中的表现,关于其原理和其余功能不做为重点叙述。数据库
准备工做
一.三个版本的jdk数组
1.openjdk15 2.graalvm21 3.openjdk11安全
二.jvm启动jvm参数并发
1. -XX:ZCollectionInterval =1 -XX:-ZProactive 定时gc,关闭主动gcjvm
2. -XX:ZAllocationSpikeTolerance = 5 不设置定时gc,zgc根据本身算法进行gc 系数为5性能
三.场景测试
测试应用:mysql分库分表中间件
1. 1000个链接循环发送请求发送sql至不一样版本jdk启动的分库分表中间件(限制单库链接数-产线环境)
2. 2000个并发,用jmeter测试tps发送sql至中间件(不限制单库链接数)
注: 场景 1 验证客户端感知(请求返回时间) 场景3 验证TPS
测试结果:
jdk15(定时gc-场景1)
graalvm21(定时gc-场景1)
jdk11(定时gc-场景1)
jdk15(不定时gc-场景1)
graalvm21(不定时gc-场景1)
jdk11(不定时gc-场景1)
jdk15(定时gc-场景2)
graalvm(定时gc-场景2)
jdk11(定时gc-场景2)
jdk15(不定时-场景2)
graalvm21(不定时-场景2)
jdk11(不定时-场景2)
注:因为是用公司机器进行测试,在进行不定时-场景2测试时,其余应用访问数据库流量变大,因此本次测试结果TPS偏小,后又通过几回测试,tps虽增大,可是仍小于定时-场景2,不影响测试结论。
结论:
cpu占用率:
graalVm21 > openjdk11 > openjdk15
堆内存使用状况
graalVm21 < openjdk15 ~ openjdk11
开始测试时出现大于200ms请求的次数(笔者所在项目关注的指标)
openjdk11 > graalvm21 > openjdk15
不定时GC JVM参数下,两次GC间隔:
openjdk15 > graalvm21 > openjdk11
2000并发下tps 为:
openjdk15 > graalvm21 ~ openjdk11
综合比较: graalVm21 和 openjdk15 ZGC内存性能相关相差不大,可是openjdk15开始压测时出现大于200ms请求量较少(即TTSP短),tps相对较高。
在本次测试中,非定时gc状况下TPS小于定时gc状况下tps
两种JVM参数下GC停顿时间99线为:
定时GC:0.845ms
非定时GC : 0.273ms
均不超过1ms
扩展:
通过本次测试,不由产生两个疑问:
1.openjdk15 的zgc相较于11作了哪些优化
2.为何定时gc下TPS比非定时gc下TPS高
问题1:通过一系列的测试和资料查找发现jdk11-15 zgc的相关优化以下(红框内为涉及本次测试优化):
1.zgc在jdk13时缩短了到达safepoint的时间(ttsp)
2.jdk14引入了安全点可识别数组分配(将初始化为0期间的数组标记为不可见根,任何大小的数组都不会影响TTSP)(不在截图内,在jdk14官方博客中能够找到相关优化介绍)
3.jdk12支持并发卸载类,而且进一步缩短了停顿时间
问题2:通过对gc日志的分析得出:
ZGC初次标记和搬运阶段定时GC平均时间小于非定时GC平均时间,由于定时GC初次标记阶段须要标记的root相对较少,搬运对象也相对较少。
因此其stw相对较小。即TPS相对较高。
思考:
本次测试并不表明全部状况下定时gc都比非定时gc更优。由于非定时gc状况下,jvm会根据配置的系数来进行GC,当流量忽然增大,会增长gc次数,频繁gc,当流量平稳时,会减小gc次数。是不一样的GC策略,实际生产应用中还须要根据不一样场景进行选择。