Java вне памяти Исключение - PullRequest
       49

Java вне памяти Исключение

7 голосов
/ 30 ноября 2009

Я использую веб-приложение на Java в Tomcat. Приложение использует Quartz Framework для регулярного планирования работы cron. Эта задача cron включает в себя анализ xml-файла размером 4+ МБ, который я выполняю с использованием JDOM API. XML-файл содержит около 3600 узлов для анализа и, следовательно, данные для обновления в БД, которые я делаю последовательно.
После анализа почти половины файла мое приложение выдает исключение нехватки памяти. Трассировка одного и того же стека:

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)

Это приводит к падению даже моего кота. Можете ли вы помочь мне в диагностике проблемы. Я даже включил профилирование в NetBeans для того же самого, но кажется, что даже это рухнуло. Я сохранил память по умолчанию, выделенную для Tomcat. Происходит ли утечка памяти? Моя БД - postgres, а JDK - 1.6.0_15.

Спасибо, Amit

Ответы [ 9 ]

10 голосов
/ 09 января 2013

Попробуйте увеличить выделение памяти для вашей виртуальной машины Java. Это должно помочь.

Исправление для затмения: вы можете настроить это в настройках затмения следующим образом

  1. Windows -> Настройки (на Mac это: eclipse -> настройки)
  2. Java -> Установленные JRE
  3. Выберите JRE и нажмите Edit
  4. в поле поля аргументов VM по умолчанию введите -Xmx1024M. (или ваши предпочтения памяти, для 1 ГБ оперативной памяти его 1024)
  5. Нажмите «Готово» или «ОК».
5 голосов
/ 30 ноября 2009

Каждый раз, когда вы используете DOM для анализа XML-файла, вы загружаете весь файл в память, и инфраструктура DOM будет использовать для его обработки примерно одинаковый размер, поэтому он будет занимать примерно вдвое больше памяти, чем ваш размер файла.

Вам нужно будет использовать SAX, анализатор событий. Хотя это может быть трудно понять в первый раз, это очень эффективно для памяти, поскольку он просто сохраняет в памяти текущий узел синтаксического анализа.

Кажется, у Java есть некоторые реализации SAX, такие как StAX , надеюсь, это поможет.

3 голосов
/ 08 мая 2014

Попробуйте увеличить выделение памяти для вашей виртуальной машины Java. Это должно помочь.

Исправление для затмения: вы можете настроить это в настройках затмения следующим образом

Windows -> Настройки (на Mac это: eclipse -> предпочтения) Java -> Установленные JRE Выберите JRE и нажмите «Изменить» для типа поля аргументов виртуальной машины по умолчанию в -Xms256m -Xmx512m -XX: MaxPermSize = 512m -XX : PermSize = 128м. (или ваши предпочтения памяти, для 1 ГБ оперативной памяти его 1024) Нажмите на готово или ОК.

2 голосов
/ 30 августа 2013

Вы должны выделить больше места для PermGenSpace JVM tomcat.

Это можно сделать с помощью аргумента JVM: -XX:MaxPermSize=128m

По умолчанию пространство PermGen составляет 64M (и оно содержит все скомпилированные классы, поэтому, если у вас много jar (классов) в вашем пути к классам, вы действительно можете заполнить это пространство).

Кроме того, вы можете контролировать размер пространства PermGen с помощью JVisualVM и даже проверять его содержимое с помощью YourKit Java Profiler

2 голосов
/ 30 ноября 2009

Синтаксический анализ XML - довольно дорогая задача. Среднему синтаксическому анализатору DOM уже понадобится как минимум пять раз пространства памяти, как большой документ XML. Вы должны принять этот факт во внимание. Чтобы не было утечки памяти где-либо еще, что привело к нехватке памяти для анализатора XML, вам действительно нужно запустить профилировщик. Дайте ему все больше памяти, удвойте доступную память и профилируйте ее. Когда вы исправили причину и устранили утечку, вы можете просто вернуться к памяти по умолчанию и провести повторную проверку. Или, если на самом деле нет никаких средств утечки, просто выделите им немного больше памяти, чем по умолчанию, чтобы все это устраивало.

Вместо этого можно также использовать более эффективный анализатор XML, например VTD-XML ( домашняя страница здесь , тесты здесь ).

1 голос
/ 30 ноября 2009

Вы пытались установить максимальный размер кучи, чтобы увидеть, если проблема все еще возникает тогда? Там может даже не быть утечки вообще. Возможно, размер кучи по умолчанию (64 м в Windows, я думаю) недостаточен для этого конкретного процесса.

Я обнаружил, что мне почти всегда нужно давать любому приложению, в котором у меня запущен Tomcat, больше кучи и места для хранения, чем по умолчанию, либо у меня возникнут проблемы с памятью. Если вам нужна помощь в настройке параметров памяти, посмотрите на этот вопрос .

0 голосов
/ 30 ноября 2009

Вы можете запустить ваше приложение с: -XX: + HeapDumpOnOutOfMemoryError. Это заставит JVM создать дамп кучи, когда ему не хватит памяти. Вы можете использовать что-то вроде: MAT или JHAT, чтобы увидеть, какие объекты удерживаются. Я предлагаю использовать анализатор памяти Eclipse (MAT) для сгенерированного дампа кучи, поскольку его довольно просто использовать: http://www.eclipse.org/mat/

Конечно, вам нужно иметь некоторое представление о том, какие объекты могут висеть вокруг, чтобы это было полезно. DOM объекты? Ресурсы из предыдущих загрузок XML-документов? Соединения с базой данных? MAT позволит вам отследить ссылки на корневой объект от некоторого объекта, который, как вы подозреваете, должен был быть подвергнут сборке мусора.

0 голосов
/ 30 ноября 2009

Я остановлюсь на этом вопросе о файле и 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 , чтобы вы могли видеть, что происходит.

0 голосов
/ 30 ноября 2009

Вы уверены, что где-то нет рекурсивной копии массива, оставленной там по ошибке? Возможно в разных темах?

...