为什么Java扔Java.lang.outofmemoryerror:Metaspace,但有很多免费的Metaspac



在我的应用程序中,我正在使用Javassist库在运行时创建很多Java类。在某个时候,抛出了java.lang.OutOfMemoryError: Metaspace,但Java流程监视(基于Java.lang.management.memorypoolmxbean)报告说有很多免费的metaspace。这是为什么?以及如何使用100%的Metaspace内存池?

我已经创建了一个最小应用程序,可以重现问题https://github.com/vlkv/java_metaspace_oom

下载它,CD到项目dir,然后执行"蚂蚁运行"。在此应用程序中,我设置了-xx:maxMetAspaceSize = 100m,但是在使用23564kb的Metaspace的某个点上抛出了OOM。

错误的调用堆栈是:

javassist.CannotCompileException: by java.lang.OutOfMemoryError: Metaspace
    at javassist.ClassPool.toClass(ClassPool.java:1170)
    at javassist.CtClass.toClass(CtClass.java:1316)
    at com.tradingview.Main.generateRandomClass(Main.java:53)
    at com.tradingview.Main.main(Main.java:24)
Caused by: java.lang.OutOfMemoryError: Metaspace
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at javassist.ClassPool.toClass2(ClassPool.java:1183)
    at javassist.ClassPool.toClass(ClassPool.java:1164)
    ... 3 more

哇,我刚找到答案。问题是,在我的应用程序中,我为每个生成的类创建一个单独的新类负载程序。我已经在示例应用程序中进行了修改,该应用程序将所有生成的类都放在一个类负载器上,此后,在Free Metaspace几乎为零时,OOM被抛弃。修复程序在这里https://github.com/vlkv/java_metaspace_oom/commit/commit/d6bcade51f797588e2413d1852c771f163392c294 branch fix_of_of_the_problem

有人知道Java过程中类加载程序的限制是什么?以及如何增加它们?

还发现了为什么Metaspace的大小是二手Metaspace的两倍?

最新更新