Skip to content

GC算法选择

Published: at 04:06 AM

前段时间生产环境一个Java应用出现了服务不可用问题,通过日志发现原来是Full GC时间过长(21.40秒),导致服务不可用。

GC日志:

[Full GC (Ergonomics) [PSYoungGen: 22184K->0K(3463168K)]
[ParOldGen: 6989862K->701860K>(6990848K)] 7012047K->701860K(10454016K),
[Metaspace: 208715K->207356K(1255424K)], 21.4039625 secs]
[Times: user=40.17 sys=114.15, real=21.40 secs]

JDK1.8垃圾回收默认使用Parallel算法。Parallel算法优点是吞吐量高,并发性。缺点也明显,暂停时间长(stop the world),对于响应时间敏感的应用来说不合适。

如何选择GC算法

GC 算法主要关注三个指标:

和很多问题一样,你没办法“全都要”,需要根据应用特点做选择。

垃圾收集器场景
Serial- 小型数据集(最大约 100 MB)
- 资源有限(例如单核)
- 暂停时间短
Parallel- 多核系统上的峰值性能
- 非常适合高计算负载
- > 1 秒的暂停是可以接受的
G1 CMS- 响应时间 > 吞吐量
- 大堆
- 暂停时间 < 1 秒
Shenandoah- 尽量减少暂停时间
- 可预测的延迟
ZGC- 响应时间是高优先级,和/或
- 非常大的堆
Epsilon GC- 性能测试和故障排除

由上面表格对比,我们需要响应优先,暂停时间短的算法,JDK1.8可以支持G1算法

启动时使用G1

java -XX:+UseG1GC

打印相关GC日志

java -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M  -jar app.jar

总结

实际测试后服务没有再出现类似延迟问题,G1还是很好用的。另外建议新的项目使用更高Java版本,比如Java21,目前也已用到生产环境,没必要守着1.8不放。

参考: