记一次JVM的FullGC问题优化实战

记一次JVM的FullGC问题优化实战

0x00 JVM启动参数

CommandLine flags:

1
-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC

0x01 问题描述

最近监控系统看到一些项目启动没多久就会发生FullGC,肯定不是正常现象,于是打开GC日志分析,

gc

其实GC原因的提示也非常明显Metadata GC Threshold说明元空间到达阈值引发的GC
从日志JVM各区域的使用量也可以分析出问题,在系统启动后的148秒都发生了FullGC,而老年代[ParOldGen: 264K->5527K(51200K)]基本没怎么使用,说明不是老年代不足引起的FullGC
而JAVA8的元空间却满了[Metaspace: 20578K->20576K(1067008K)],这里也可以基本定位到是元空间的问题了,并且每一次FullGC后元空间都会扩容。

0x02 原因描述

那么为什么会引发元空间的GC呢,自动JAVA8将永久代替换成元空间之后,Metaspaces是保存在本地内存中,是没有上限的,而从每次FullGC后元空间发生的扩容可以分析出默认值太小引起的GC扩容
那么我们来查询jvm默认的元空间大小,使用命令java -XX:+PrintFlagsInitial查看本机的初始化参数
gc
可以在截图中看到-XX:Metaspacesize为21810376B (大约20M) 问题就出在这里。
code量较大的项目启动会因为Metaspace默认值较小而引发GC来扩容

0x03 解决办法

既然知道了原因是因为初始值太小,那么我们根据项目情况设置一个合适的大小就行了
-XX:MetaspaceSize=128M