[英]Java out of memory Exception
我正在 Tomcat 中運行 Java Web 應用程序。 該應用程序使用 Quartz 框架定期調度 cron 作業。 此 cron 作業涉及解析 4 MB 以上的 xml 文件,我正在使用 JDOM API 進行解析。 xml 文件包含大約 3600 個要解析的節點,因此要在我按順序執行的 DB 中更新數據。
解析幾乎一半的文件后,我的應用程序拋出內存不足異常。 相同的堆棧跟蹤是:
Exception in thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3210)
at java.lang.String.<init>(String.java:216)
at java.lang.StringBuffer.toString(StringBuffer.java:585)
at org.netbeans.lib.profiler.server.ProfilerRuntimeMemory.traceVMObjectAlloc(ProfilerRuntimeMemory.java:170)
at java.lang.Throwable.getStackTraceElement(Native Method)
at java.lang.Throwable.getOurStackTrace(Throwable.java:590)
at java.lang.Throwable.getStackTrace(Throwable.java:582)
at org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:155)
at org.apache.juli.logging.DirectJDKLog.error(DirectJDKLog.java:135)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1603)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "*** JFluid Monitor thread ***" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2760)
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.Vector.ensureCapacityHelper(Vector.java:226)
at java.util.Vector.add(Vector.java:728)
at org.netbeans.lib.profiler.server.Monitors$SurvGenAndThreadsMonitor.updateSurvGenData(Monitors.java:230)
at org.netbeans.lib.profiler.server.Monitors$SurvGenAndThreadsMonitor.run(Monitors.java:169)
Nov 30, 2009 2:22:05 PM org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor processChildren
SEVERE: Exception invoking periodic operation:
java.lang.OutOfMemoryError: Java heap space
at java.lang.StringCoding$StringEncoder.encode(StringCoding.java:232)
at java.lang.StringCoding.encode(StringCoding.java:272)
at java.lang.String.getBytes(String.java:946)
at java.io.UnixFileSystem.getLastModifiedTime(Native Method)
at java.io.File.lastModified(File.java:826)
at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1175)
at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1269)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:296)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:118)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
at java.lang.Thread.run(Thread.java:619)
ERROR [JobRunShell]: Job updateVendorData.quoteUpdate threw an unhandled Exception:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3210)
at java.lang.String.<init>(String.java:216)
at java.lang.StringBuffer.toString(StringBuffer.java:585)
at org.apache.commons.dbcp.PoolingConnection$PStmtKey.hashCode(PoolingConnection.java:296)
at java.util.HashMap.get(HashMap.java:300)
at org.apache.commons.pool.impl.GenericKeyedObjectPool.decrementActiveCount(GenericKeyedObjectPool.java:1085)
at org.apache.commons.pool.impl.GenericKeyedObjectPool.returnObject(GenericKeyedObjectPool.java:882)
at org.apache.commons.dbcp.PoolablePreparedStatement.close(PoolablePreparedStatement.java:80)
at org.apache.commons.dbcp.DelegatingStatement.close(DelegatingStatement.java:168)
at com.netcore.smsapps.stock.db.CompanyDaoImpl.updateCompanyQuote(CompanyDaoImpl.java:173)
at com.netcore.smsapps.stock.vendor.MyirisVendor.readScripQuotes(MyirisVendor.java:159)
at com.netcore.smsapps.stock.update.StockUpdateData.execute(StockUpdateData.java:38)
at org.quartz.core.JobRunShell.run(JobRunShell.java:207)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
DEBUG [ExceptionHelper]: Detected JDK support for nested exceptions.
ERROR [ErrorLogger]: Job (updateVendorData.quoteUpdate threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.OutOfMemoryError: Java heap space]
at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3210)
at java.lang.String.<init>(String.java:216)
at java.lang.StringBuffer.toString(StringBuffer.java:585)
at org.apache.commons.dbcp.PoolingConnection$PStmtKey.hashCode(PoolingConnection.java:296)
at java.util.HashMap.get(HashMap.java:300)
at org.apache.commons.pool.impl.GenericKeyedObjectPool.decrementActiveCount(GenericKeyedObjectPool.java:1085)
at org.apache.commons.pool.impl.GenericKeyedObjectPool.returnObject(GenericKeyedObjectPool.java:882)
at org.apache.commons.dbcp.PoolablePreparedStatement.close(PoolablePreparedStatement.java:80)
at org.apache.commons.dbcp.DelegatingStatement.close(DelegatingStatement.java:168)
at com.netcore.smsapps.stock.db.CompanyDaoImpl.updateCompanyQuote(CompanyDaoImpl.java:173)
at com.netcore.smsapps.stock.vendor.MyirisVendor.readScripQuotes(MyirisVendor.java:159)
at com.netcore.smsapps.stock.update.StockUpdateData.execute(StockUpdateData.java:38)
at org.quartz.core.JobRunShell.run(JobRunShell.java:207)
這甚至會導致我的 tomcat 崩潰。 你能幫我診斷問題嗎? 我什至在 Netbeans 中啟用了相同的分析,但似乎甚至崩潰了。 我保留了分配給 Tomcat 的默認內存。 是否發生了內存泄漏。 我的數據庫是 postgres,JDK 是 1.6.0_15。
謝謝,阿米特
嘗試增加 JVM 的 ram 分配。 它應該有幫助。
修復 eclipse:您可以在 eclipse 首選項中進行如下配置
每次使用 DOM 解析 XML 文件時,都會將整個文件加載到內存中,DOM 基礎架構將使用大致相同的大小來處理它,因此它消耗的內存大約是文件大小的兩倍。
您需要使用 SAX,一種基於事件的解析器。 雖然這可能很難第一次理解,但它是一種非常有效的記憶方法,因為它只保留在內存中的當前解析節點。
似乎 Java 有一些 SAX 實現,比如StAX ,我希望它有所幫助。
嘗試增加 JVM 的 ram 分配。 它應該有幫助。
修復 Eclipse
您可以在 Eclipse 的首選項中進行如下配置:
Windows -> 首選項(在 Mac 上為:Eclipse -> 首選項)Java -> 已安裝的 JRE
選擇 JRE 並在-Xms256m -Xmx512m -XX:MaxPermSize=512m -XX:PermSize=128m
(或您的內存偏好,對於 1 gb ram 為 1024)中的默認 VM 參數字段類型上單擊“編輯”。 單擊完成或確定。
您必須為 tomcat JVM 的 PermGenSpace 分配更多空間。
這可以通過 JVM 參數來完成: -XX:MaxPermSize=128m
默認情況下,永久代空間為 64M(並且它包含所有已編譯的類,因此如果您的類路徑中有很多 jar(類),您可能確實會填滿這個空間)。
附帶說明一下,您可以使用JVisualVM監控 PermGen 空間的大小,甚至可以使用YourKit Java Profiler檢查其內容
您是否嘗試將最大堆大小設置得更大以查看問題是否仍然存在? 甚至可能根本沒有泄漏。 可能只是默認堆大小(我認為在 Windows 上為 64m)對於這個特定進程來說是不夠的。
我發現我幾乎總是需要為我運行 Tomcat 的任何應用程序提供比默認值更多的堆和永久生成空間,否則我會遇到內存不足的問題。 如果您需要幫助調整內存設置,請查看此問題。
您確定某處沒有遞歸數組副本,而是錯誤地留在那里嗎? 也許在不同的線程中?
我將就文件和 DOM 占用大量內存的這一點進行第二次說明。 我也想知道什么時候看到這個:
ERROR [JobRunShell]: Job updateVendorData.quoteUpdate threw an unhandled Exception:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3210)
那個抄襲干什么? 我想知道您的代碼中是否還有其他不好的地方。
如果您已經到了這一步,則表明您已成功讀取文件和 DOM,並且您正在開始寫入數據庫。 文件內存應該已經被回收了。
我建議使用VisualGC查看內存,以便您了解發生了什么。
您可以使用以下命令運行您的應用程序:-XX:+HeapDumpOnOutOfMemoryError。 這將導致 JVM 在內存不足時產生堆轉儲。 您可以使用諸如:MAT 或 JHAT 之類的東西來查看所持有的對象。 我建議在生成的堆轉儲上使用 eclipse 內存分析器工具 (MAT),因為它使用起來相當簡單: http : //www.eclipse.org/mat/
當然,您需要對哪些對象可能掛在周圍有一些想法,以便它有用。 DOM 對象? 來自先前加載的 xml 文檔的資源? 數據庫連接? MAT 將允許您從某個您懷疑應該被垃圾回收的對象中跟蹤對根對象的引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.