java 8 java.lang.OutOfMemoryError:Metaspace

问题描述 投票:0回答:1

我在运行Java cs应用程序时遇到OutOfMemoryError。根据错误消息,似乎在将XML String传输到Java对象时发生错误。

转移代码如下

public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
    Object xmlObject = null;
    try {
        JAXBContext context = JAXBContext.newInstance(clazz);
        // 进行将Xml转成对象的核心接口
        Unmarshaller unmarshaller = context.createUnmarshaller();
        StringReader sr = new StringReader(xmlStr);
        xmlObject = unmarshaller.unmarshal(sr);
    } catch (JAXBException e) {
        e.printStackTrace();
    }
    return xmlObject;
}

我查看了我的日志并找到了触发此错误的String。然后我使用上面的代码将此String转换为java对象,持续10K次。没有报告错误。

我有成千上万的这样的应用程序在Windows XP系统中运行,我担心这可能会导致一个巨大的问题。我用Google搜索了这个错误,许多人说错误发生是因为MaxMetaspaceSize太小了,而我没有在我的应用程序中使用MaxMetaspaceSize。

java.lang.OutOfMemoryError: Metaspace
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.<init>(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl.newSAXParser(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.getXMLReader(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at com.hgits.payCodeDebit.util.XMLUtil.convertXmlStrToObject(XMLUtil.java:91)

检查最近的日志后,我发现了一个奇怪的问题。除了上面的错误,还有另一个错误,如下所示:

java.io.IOException: Map failed
at sun.nio.ch.FileChannelImpl.map(Unknown Source)
at sun.nio.ch.FileChannelImpl.transferFromFileChannel(Unknown Source)
at sun.nio.ch.FileChannelImpl.transferFrom(Unknown Source)
at org.apache.commons.io.FileUtils.doCopyFile(FileUtils.java:1147)
at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:1091)
at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:1038)
at com.hgits.cron.CheckNonFareParamJob.checkRecvParamList(CheckNonFareParamJob.java:153)
at com.hgits.cron.CheckNonFareParamJob.execute(CheckNonFareParamJob.java:54)
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557)
Caused by: java.lang.OutOfMemoryError: Map failed
at sun.nio.ch.FileChannelImpl.map0(Native Method)
... 10 more

谷歌搜索后,这似乎是一个记忆问题。我用jna和windows api GetProcessMemoryInfo来ping进程内存。当我的应用程序启动时,jvm进程内存为615616K,这是正常的,一切正常。运行大约36个小时后,jvm进程内存达到1796676K,我开始出现“java.lang.OutOfMemoryError:Map failed”错误。当jvm进程内存达到1796676K时,我还记录了jvm的堆内存,其低于810942464byte(Runtime.getRuntime()。maxMemory()):810942464byte(Runtime.getRuntime()。totalMemory()):239632736byte(运行时。 getRuntime()。freeMemory())。所以在jvm堆中仍然有200M freeMemory。

因为我使用jna加载了几个dll,我的猜测是某些dll中存在某种内存泄漏。如果我猜对了,我怎么找到原因?我试过jjvisualvm和jmc,但我没有看错。

java out-of-memory
1个回答
2
投票

我可以想到几个解释:

  1. 一些XML解析器习惯于实习字符串。如果您正在进行大量的XML解析,这会将大量字符串数据放入字符串池中......这是在元空间中。如果仍然可以访问字符串(例如,因为DOM可以访问,或者因为您将它们保存在另一个数据结构中),则可以填充元空间。
  2. 在幕后,您的应用程序中的某些内容可能会进行大量的类加载。例如,如果您广泛使用动态代理。这可以将很多不可收集的类放入元空间,最终填充它。
  3. JAXBContext初始化可能会创建动态代理(请参阅上一点)。正如@PaulBastide所指出的,你应该能够创建一个JAXBContext并重复使用它。除了提高效率之外,这样做可以解决元空间泄漏问题。

增加元空间的大小是一种创可贴解决方案。更好的想法是让JVM在OOME时创建堆转储并分析转储以找出使用这么多元空间的内容。然后决定是否是你可以解决的问题,或者是否使用-XX:MetaspaceSize=...创可贴并希望最好。


这是相当晚的,但你导致java.lang.OutOfMemoryError: Map failed的问题不是普通的内存泄漏;即Java堆对象或本机堆对象的泄漏。它根本不是泄漏。

发生的事情是你的代码正在尝试将文件映射到内存中。 JVM要求操作系统提供一个大内存段来保存文件,操作系统会说“不”。这可能有很多原因:

  1. 您尝试映射的文件可能太大了。
  2. 您的应用程序可能已经映射了许多其他文件,但未能取消映射它们。 (那将是一个泄漏。)
  3. 您的JVM进程可能存在“ulimit”或类似限制。
  4. 如果您运行的是32位JVM,则可能会遇到32位虚拟地址空间限制。
© www.soinside.com 2019 - 2024. All rights reserved.