Как определить причину OutofMemoryError?

У меня есть жалоба на то, что мое серверное приложение рушится при высокой нагрузке.
Это веб-приложение, работающее в Tomcat 5.
Я вижу дампы потоков, и я вижу, что есть ошибка OutOfMemory

Событие дампа 1TISIGINFO "systhrow" (00040000) Подробности
"java/lang/OutOfMemoryError" "Не удалось создать поток: retVal -1073741830, errno 12" > получен 1TIDATETIME Дата: 2012/07/17 в 20:03:17 1TIFILENAME > Javacore имя файла: C:\ServerApplication\Tomcat5\bin\javacore.34545719.4646464.4172.0003.txt

Информация о куче следующая:

Maximum Java heap size : 1500m    
Initial Java heap size : 256m

Это конфигурация начального и максимального размера кучи (32-битная java)

Я также вижу, что доступно свободное пространство кучи

1STHEAPFREE    Bytes of Heap Space Free: 2D19F3C0   
1STHEAPALLOC   Bytes of Heap Space Allocated: 5DC00000

Это объем свободного пространства 750 МБ, не так ли?

И из анализа метода потока я вижу, что число потоков 695, из которых 49% равно java/lang/Object.wait(Native Method) и 39% находится в sun/misc/Unsafe.park(Native Method)
Также я вижу, что это NO JAVA STACK 1% не уверен, что это значит.
Также 0 тупиков зашли в тупик, а 2% - Runnable.

Я не уверен, как интерпретировать эту информацию или как продолжить здесь, чтобы обнаружить основную причину. Любая помощь по этому поводу?

Ответ 1

Согласно этот пост:

Есть две возможные причины java.lang.OutOfMemoryError: Не удалось создать сообщение с потоком:

  • Слишком много потоков запущено, и в системе не хватает внутренних ресурсов для создания новых потоков.
  • У системы закончилась встроенная память для использования в новом потоке. Для потоков требуется встроенная память для внутренних структур JVM, Java ™ стек и собственный стек.

Таким образом, эта ошибка вполне может быть полностью не связана с памятью, просто создается слишком много потоков...

EDIT:

Поскольку у вас есть 695 потоков, вам потребуется 695 раз размер стека в качестве памяти. Учитывая этот пост в потоковых ограничениях, я подозреваю, что вы пытаетесь создать слишком много потоков для доступного пространства виртуальной памяти.

Ответ 2

Вы должны запустить JVM с флагом -XX:+HeapDumpOnOutOfMemoryError. Это приведет к созданию дампа кучи при создании OutOfMemoryError.

Затем, как сказал @Steve, вы можете использовать такой инструмент, как MAT, для анализа дампа и просмотра, какие объекты выделены, и кто держит ссылки на них. Это, как правило, даст вам некоторое представление о том, почему ваша JVM исчерпывает свою память.

Ответ 3

Я знаю, что вы имеете в виду, может быть запутанным найти где-то начать.

Посмотрите Eclipse Memory Analyzer (MAT). Он будет использовать JHat для удаления моментального снимка памяти вашей программы в файл, который вы можете повторно открыть и проанализировать.

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


Добавление моих комментариев для ответа...

Справа, когда ваш исполняемый сбой webapp падает, выгрузите его в MAT. MAT расскажет вам, какой объект создается несколько раз. Если это пользовательский объект, и он часто бывает, его легко найти. Если нет, вы можете увидеть его родителя, ампутировать его и оттуда оттуда (извините за графический пример, я не совсем сосредоточен на SO в данный момент:).

О, и я забыл упомянуть, вы можете запускать программу несколько раз при нескольких условиях и каждый раз создавать дамп. Затем вы можете проанализировать каждый дамп для тренда.


Но в моем случае, что я должен использовать? У меня есть веб-приложение, работающее в Tomcat

Извините, пропустил это тоже. Если я не ошибаюсь, MAT сбрасывает процесс JVM, поэтому пока VM работает на вашем ящике, вы можете сбросить его процесс и посмотреть, что происходит.


Другой комментарий, мутированный в частичное решение...

Это становится все труднее, чем на самом деле. Серьезно, это довольно легко, после того, как вы запускаете MAT один или два раза, чтобы повесить вещи. Запустите приложение до сбоя. Сбросьте это. Что-то измените. Выполнить, сбой, сброс. Повторение. Затем откройте дампы в MAT и сравните то, что выглядит подозрительным.

Самая сложная часть, когда я изучала это, находила идентификатор процесса для дампа - который все еще не слишком ошеломляющий.

Ответ 4

Аналогичное сообщение в IBM WebSphere показывает эту строку

"Не удалось создать поток: retVal"

как указание на собственный OOM, что означает, что какой-то поток (процесса) пытается запросить большую часть памяти в куче.

В приведенной выше ссылке IBM есть несколько этапов: некоторые из них являются специфичными для IBM. Посмотрите.

С точки зрения использования собственной памяти:

  • Максимальные настройки кучи Java
  • Драйвер JDBC
  • Код JNI или родные библиотеки
  • сбор мусора неиспользуемых классов. Ensurethat -Xnoclassgc не установлен.
  • Настройки пула потоков (пулы потоков с фиксированным размером)
  • Слишком много загрузчиков классов и т.д., но они не очень распространены.
  • Количество классов/загрузчиков классов из javacores.

Еще одна вещь, на которую вы могли бы обратить внимание, - это PermGenSpace - насколько она велика?

Эта ссылка http://www.codingthearchitecture.com/2008/01/14/jvm_lies_the_outofmemory_myth.html предлагает

Увеличение распределения кучи фактически усугубляет эту проблему! Это уменьшает запас запаса компилятора и другие нативные компоненты, играть с. Поэтому решение моей проблемы было:  1. восстановить кучу, выделенную для JVM. 2. Удалите утечки памяти, вызванные тем, что нативные объекты не освобождаются своевременно.

Также вы настроили значение в server.xml для maxThreads? По умолчанию 200, но ваше приложение имеет 695?

Ответ 5

Fix

Следование техническому обеспечению IBM java.lang.OutOfMemoryError при создании новых потоков, в частности команда "ulimit" для увеличения значения по умолчанию по умолчанию 1024.

Проблема

[2/25/15 12:47:34:629 EST] 00000049 SystemErr     R java.lang.OutOfMemoryError: Failed to create a thread: retVal -1073741830, errno 11
[2/25/15 12:47:34:630 EST] 00000049 SystemErr     R     at java.lang.Thread.startImpl(Native Method)
[2/25/15 12:47:34:630 EST] 00000049 SystemErr     R     at java.lang.Thread.start(Thread.java:936)
[2/25/15 12:47:34:630 EST] 00000049 SystemErr     R     at org.eclipse.osgi.framework.internal.core.InternalSystemBundle.stop(InternalSystemBundle.java:251)
[2/25/15 12:47:34:630 EST] 00000049 SystemErr     R     at com.ibm.ws.runtime.component.RuntimeBundleActivator.shutdownEclipse(RuntimeBundleActivator.java:54)
[2/25/15 12:47:34:630 EST] 00000049 SystemErr     R     at com.ibm.ws.runtime.component.ServerCollaborator$ShutdownHook$1.run(ServerCollaborator.java:878)
[2/25/15 12:47:34:630 EST] 00000049 SystemErr     R     at com.ibm.ws.security.auth.ContextManagerImpl.runAs(ContextManagerImpl.java:5459)
[2/25/15 12:47:34:631 EST] 00000049 SystemErr     R     at com.ibm.ws.security.auth.ContextManagerImpl.runAsSystem(ContextManagerImpl.java:5585)
[2/25/15 12:47:34:631 EST] 00000049 SystemErr     R     at com.ibm.ws.runtime.component.ServerCollaborator$ShutdownHook.run(ServerCollaborator.java:850)
[2/25/15 12:47:34:631 EST] 00000049 SystemErr     R     at com.ibm.ws.runtime.component.ServerCollaborator$StopAction.alarm(ServerCollaborator.java:809)
[2/25/15 12:47:34:631 EST] 00000049 SystemErr     R     at com.ibm.ejs.util.am._Alarm.run(_Alarm.java:133)
[2/25/15 12:47:34:631 EST] 00000049 SystemErr     R     at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1815)

Окружающая среда

CentOS 6.6 64 бит IBM WAS 8.5.0.2 64 бит

Ссылки