fullgc问题解决:Full GC (Metadata GC Threshold)

#问题描述
在工作过程中,遇到一个问题:Tomcat在重启或者发布的时候,会有多次的full GC。

笔者使用的版本说明:
Tomcat7.0.25
JDK8

首先排查JVM的问题,就要把GC日志打开

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

重启Tomcat服务器,发现gc日志如下:
fullgc问题解决:Full GC (Metadata GC Threshold)_第1张图片

原因描述

通过GC日志可以看到,old区离最大配置还很远,Metaspace区并没有真正释放空间,所以怀疑是Metaspace区不够用了。

以前只认为,Metaspace区是保存在本地内存中,是没有上限的,经查阅资料才发现,原来JDK8中,XX:MaxMetaspaceSize确实是没有上限的,最大容量与机器的内存有关;但是XX:MetaspaceSize是有一个默认值的:21M。问题就出在这里。
fullgc问题解决:Full GC (Metadata GC Threshold)_第2张图片

最终解决方案

既然问题找到了,那么就设置一个XX:MetaspaceSize的JVM启动参数:-XX:MetaspaceSize=128M.

Metaspace配置说明

从JDK8开始,永久代(PermGen)的概念被废弃掉了,取而代之的是一个称为Metaspace的存储空间。Metaspace使用的是本地内存,而不是堆内存,也就是说在默认情况下Metaspace的大小只与本地内存大小有关。当然你也可以通过以下的几个参数对Metaspace进行控制:

-XX:MetaspaceSize=N
这个参数是初始化的Metaspace大小,该值越大触发Metaspace GC的时机就越晚。随着GC的到来,虚拟机会根据实际情况调控Metaspace的大小,可能增加上线也可能降低。在默认情况下,这个值大小根据不同的平台在12M到20M浮动。使用java -XX:+PrintFlagsInitial命令查看本机的初始化参数,-XX:Metaspacesize21810376B(大约20.8M)。
在这里插入图片描述
-XX:MaxMetaspaceSize=N
这个参数用于限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。在本机上该参数的默认值为4294967295B(大约4096MB)。

-XX:MinMetaspaceFreeRatio=N
当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数,那么虚拟机将增长Metaspace的大小。在本机该参数的默认值为40,也就是40%。设置该参数可以控制Metaspace的增长的速度,太小的值会导致Metaspace增长的缓慢,Metaspace的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致Metaspace增长的过快,浪费内存。

-XX:MaxMetasaceFreeRatio=N
当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。在本机该参数的默认值为70,也就是70%。

-XX:MaxMetaspaceExpansion=N
Metaspace增长时的最大幅度。在本机上该参数的默认值为5452592B(大约为5MB)。

-XX:MinMetaspaceExpansion=N
Metaspace增长时的最小幅度。在本机上该参数的默认值为340784B(大约330KB为)。

参考资料

第一次FullGC优化实战
JVM之永久区Permanent区参数设置分析
Metaspace

你可能感兴趣的:(jvm)