如何诊断 Java 8 元空间泄漏?

Posted

技术标签:

【中文标题】如何诊断 Java 8 元空间泄漏?【英文标题】:How to diagnose a Java 8 metaspace leak? 【发布时间】:2015-06-08 00:34:57 【问题描述】:

我有一个具有一些有趣行为的 J2EE 应用程序......堆似乎表现良好,随着时间的推移随着垃圾收集而增长和缩小。没有明显的整体长期堆扩展。然而,元空间以每小时 20 Mb 的速度稳定增长,直到我们到达 MaxMetaspace 并遇到 OOME。我已经尝试过并行和 G1 垃圾收集器 (jdk1.8.0_40)。

应用程序在执行过程中没有被重新部署,所以它看起来不像是典型的类加载器泄漏。有没有人对如何追踪泄漏的来源有任何建议?

【问题讨论】:

你找到答案了吗? 您能否提供更多信息:JEE 服务器、使用的库。 这是尝试在 Java 8 下的 JBoss 4.2.3.GA 上运行旧版 J2EE 应用程序。这不是受支持的配置,但客户确实想尝试一下。我知道从那时起 JBoss 类加载发生了重大变化,所以我怀疑这是类加载器问题。下面菲利普关于代理生成的猜测可能有一些优点。我们最终决定“咬紧牙关”,将应用程序移植到 Wildfly 8。 我也遇到过类似的问题,我们使用wildfly 10,多次重新部署app Metaspace 后抛出oom 错误。增加最大元空间只是一种解决方法,而不是解决方案。我还没有找到任何解决方案。 【参考方案1】:

进行堆转储并使用Eclipse MAT 对其进行分析。查看您已加载的类。检查是否有意外情况,尤其是重复的类。它还有一个类加载器资源管理器。

编辑: 从理论上讲,您也可能是不断生成代理。

【讨论】:

我们尝试了 MAT 类加载器资源管理器。不幸的是,该应用程序足够繁忙和复杂,并且泄漏速度足够慢,以至于它仍然是“大海捞针”的提议。无论如何,这种配置本来是一种临时解决方案,但我们达到了收益递减的地步,所以我们放弃了。 我不知道 WildFly 问题。 OP 从来没有调试过这个问题,所以它可能是任何东西,包括他/她的应用程序。【参考方案2】:

java.lang.OutOfMemoryError: Metaspace 的主要原因是:

类太多类太大正在加载到元空间。

如果您想重现问题,请使用以下代码 sn-p:

public class Metaspace 
static javassist.ClassPool cp = javassist.ClassPool.getDefault();

public static void main(String[] args) throws Exception 
    for (int i = 0; ; i++)  
        Class c = cp.makeClass("eu.plumbr.demo.Generated" + i).toClass();
    
  

所有这些生成的类定义最终都会消耗元空间。

Maven repo 中的 Javaassist。

您可以找到更多关于 OOME here

【讨论】:

嗨,我在清理 javassist.ClassPool 对象时遇到问题。这是怎么做到的?

以上是关于如何诊断 Java 8 元空间泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

java 8中撤销永久代,引入元空间

在 Wildfly 8.2.1 上部署的 Java 8 应用程序的元空间内存消耗问题

主元分析法是啥?

JVM 内存结构

元空间大小

Java8内存模型—方法区 (old:永久代 new:元空间)