簡體   English   中英

java 8 java.lang.OutOfMemoryError:元空間

[英]java 8 java.lang.OutOfMemoryError: Metaspace

我在運行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轉換為java對象大約10K次。沒有錯誤報告。

我在Windows XP系統中運行着成千上萬個這樣的應用程序,我擔心這可能會引起很大的問題。 我用谷歌搜索了這個錯誤,很多人說該錯誤是因為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掠過了進程內存。 當我的應用程序啟動時,jvm進程內存為615616K,這是正常的,一切正常。 運行約36小時后,jvm進程內存達到1796676K,並且我開始出現“ java.lang.OutOfMemoryError:映射失敗”錯誤。 當jvm進程內存達到1796676K時,我還記錄了jvm的堆內存,如下所示:810942464byte(Runtime.getRuntime()。maxMemory()):810942464byte(Runtime.getRuntime()。totalMemory()):239632736byte(Runtime。 getRuntime()。freeMemory())。 因此,jvm堆中仍然有200M freeMemory。

因為我使用jna加載了多個dll,所以我猜測某些dll中存在某種內存泄漏。 如果我的猜測是正確的,如何找到原因? 我已經嘗試過jjvisualvm和jmc,但是我沒有發現任何錯誤。

我可以想到一些解釋:

  1. 一些XML解析器習慣於內部字符串。 如果您要進行大量的XML解析,則會將大量的字符串數據放入位於元空間的字符串池中。 如果字符串仍然可以訪問(例如,因為DOM可以訪問,或者因為您將它們保存在另一個數據結構中),則可以填充元空間。

  2. 在幕后,應用程序中的某些內容可能會進行大量的類加載。 例如,如果您廣泛使用動態代理。 這樣可以將許多不可收集的類放入元空間,最終將其填充。

  3. JAXBContext初始化可能會創建動態代理(請參見上一點)。 正如@PaulBastide指出的那樣,您應該能夠創建單個JAXBContext並重用它。 這樣做不僅效率更高,而且可以解決元空間泄漏問題。

增加元空間的大小是一個創可貼解決方案。 一個更好的主意是讓JVM在OOME時創建一個堆轉儲,並分析轉儲以弄清楚正在使用多少元空間。 然后確定這是您可以解決的問題,還是使用-XX:MetaspaceSize=...創可貼並希望達到最佳效果。


這已經很晚了,但是導致java.lang.OutOfMemoryError: Map failed的問題java.lang.OutOfMemoryError: Map failed不是普通的內存泄漏; 即Java堆對象或本機堆對象的泄漏。 可能根本不是泄漏。

發生的事情是您的代碼正在嘗試將文件映射到內存中。 JVM要求操作系統提供一個較大的內存段來保存文件,並且操作系統說“否”。 原因可能有很多:

  1. 您嘗試映射的文件可能太大了。
  2. 您的應用程序可能已經映射了許多其他文件,但無法取消映射它們 (那將是一個泄漏。)
  3. 您的JVM進程可能存在“ ulimit”或類似的限制。
  4. 如果運行的是32位JVM,則可能已達到32位虛擬地址空間限制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM