Metaspace内存溢出原因分析

1,793 阅读2分钟

Metaspace如何触发内存溢出?

如下两个参数专门设置Metaspace区大小:

  • -XX:MetaspaceSize=512m
  • -XX:MaxMetaspaceSize=512m

图中就限定Metaspace区内存为512m:

img

所以在JVM中,Metaspace区大小固定,如512M。一旦JVM不停加载很多类,然后Metaspace区满,会如何?

img

Metaspace区满就会触发Full GC,Full GC就会尝试回收Metaspace区中的类:

img

所以一旦Metaspace区满,就会触发Full GC,连带着回收Metaspace里的类。

啥样的类才会被回收呢?

条件苛刻,包括但不限于:

  • 这个类的类加载器先要被回收
  • 这个类的所有对象实例都要被回收

所以,一旦你的Metaspace区满,未必能回收掉里面很多的类。而一旦回收不了,而JVM还在拼命加载类放到Metaspace,会咋样呢?

一旦你尝试回收Metaspace中的类后,发现还是没能腾出太多空间,此时还要继续往Metaspace塞更多的类,就会引发内存溢出。因为此时Metaspace区内存空间不够了。一旦内存溢出,说明JVM已无法继续运行,系统可能就直接崩溃了。

何时会发生Metaspace内存溢出?

Metaspace很少发生内存溢出,如发生一般都是因为:

  • 很多工程师不懂JVM运行原理,在上线系统的时候对Metaspace区直接用默认参数。导致默认的Metaspace区域可能才几十M,对一个稍大型系统,因为他自己有很多类,还依赖很多外部jar包有很多类,几十MB的Metaspace很容易就不够了

    有经验的工程师上线系统往往会设置对应的Metaspace大小,推荐的值在512MB那样,一般都是足够的。

  • 很多人写系统的时候会用cglib之类动态生成一些类,一旦代码中没有控制好,导致你生成的类过于多的时候,就很容易把Metaspace给塞满,进而引发内存溢出

总结

合理分配Metaspace区域,同时避免无限制动态生成类,一般这块区域其实都是比较安全的,不至于会触发内存溢出。