结论:使用 G1 GC,JDK 11 相对于 JDK 8 来说性能明显下降。
3原因分析
=====
从 JDK 8 到 JDK 11, G1 GC 做了非常多的优化用于提高性能。为什么 JDK 11 对于应用者来说更不友好?简单的总结一下从 JDK 8 到 JDK 11 做得一些比较大的设计变化,如下表所示:
由于从 JDK 8 到 JDK 11 特性变化太多,对于这样的性能下降问题,为了能快速有效的解决,我们做了如下的尝试。
3.1统一 JDK 8 和 JDK 11 的参数,验证效果
=============================
由于 JDK 11 和 JDK 8 实现变化很多,部分功能完全不同,但是这些变化的功能一般都有参数控制,一种有效的尝试:梳理 JDK 8 和 JDK 11 关于 G1 的参数,将它们设置为相同的值,比如关闭 IHOP 的自适应,关闭线程调整等。这里简单的给出 JDK 8 和 JDK 11 不同参数的比较,如下图所示:
将两者参数都设置为和 JDK 8 一样的值,重新验证测试,结果不变,JDK 11 性能仍然下降。
3.2GC日志分析,确定JDK 11性能下降点
=======================
对于 JDK 8 和 JDK 11 同时配置日志收集功能,重新测试,获得 GC 日志。通过 GC 日志分析,我们发现差异主要在 G1 young gc 的 object copy 阶段(耗时基本在这),JDK 11 的 Young GC 耗时大概 200ms,JDK 8 的 Young GC 耗时大概 100ms,两者设置的目标停顿时间都是 100ms。
JDK 11 中 GC 日志片段:
JDK 8中 GC 日志片段:
我们对整个日志做了统计,有以下发现:
并发标记时机不同,混合回收的时机也不同;
单次 GC 中对象复制的耗时不同,JDK 11 明显更长;
总体 GC 次数 JDK 11 得更多,包括了并发标记的停顿次数;
总体 GC 的耗时 JDK 11 更多。