MetaspaceSize的坑

这几天生产上有台机器的Metaspace一直在告警,Metaspace使用达到了97%。使用-XX:MetaspaceSize=512m,告警也还在在持续,查看MC只有81536.0,显然这个参数没起作用。

也有人遇到类似的问题,并在openjdk上提过类似的bug,其实是一个注释的bug,最终在JDK-8151845中修复了。

Class metadata is deallocated when the corresponding Java class is unloaded. Java classes are unloaded as a result of garbage collection, and garbage collections may be induced in order to unload classes and deallocate class metadata. When the space committed for class metadata reaches a certain level (a high-water mark), a garbage collection is induced. After the garbage collection, the high-water mark may be raised or lowered depending on the amount of space freed from class metadata. The high-water mark would be raised so as not to induce another garbage collection too soon. The high-water mark is initially set to the value of the command-line option MetaspaceSize. It is raised or lowered based on the options MaxMetaspaceFreeRatio and MinMetaspaceFreeRatio. If the committed space available for class metadata as a percentage of the total committed space for class metadata is greater than MaxMetaspaceFreeRatio, then the high-water mark will be lowered. If it is less than MinMetaspaceFreeRatio, then the high-water mark will be raised.

查看了Oracle的手册,Metaspace的GC会在committed size达到high-water mark之后发生。并且GC之后high-water mark会变化:变大或者变小,变大的话会防止下次GC发生得太早。high-water mark的默认初始大小20.8M,通过MetaspaceSize来设置,可见MetaspaceSize是控制Metaspace发生GC的阈值。GC后high-water mark的变化,通过MaxMetaspaceFreeRatio和MinMetaspaceFreeRatio控制。

MaxMetaspaceSize默认为-1,无限大。不过如果没有限制的话,一直增大会被系统干掉进程。最好还是设置一下,比如1G。

下面是我测试了分别设置MetaspaceSize、MaxMetaspaceSize、InitialBootClassLoaderMetaspaceSize为1G,Metaspace的变化。

-XX:MetaspaceSize=1024m > committed: 29360128 > init: 0 > max: -1 > used: 28440648

-XX:MaxMetaspaceSize=1024m > committed: 29360128 > init: 0 > max: 1073741824 > used: 28503552

-XX:InitialBootClassLoaderMetaspaceSize=1024m > committed: 1087635456 > init: 0 > max: -1 > used: 28500344

三个参数都是没有改变init的大小,但是InitialBootClassLoaderMetaspaceSize改变了committed的大小,其实也是最终我们要的设置。

关于这个参数,可以看你假笨的关于Metaspace的源码解读,发现的有点晚了。

最后的解决方案是使用这个配置:-XX:MaxMetaspaceSize=1024m -XX:InitialBootClassLoaderMetaspaceSize=256m

Comments

comments powered by Disqus