jvm: возможно ли узнать, что процесс завершается из-за OOM, когда он находится в ловушке завершения работы? - PullRequest
5 голосов
/ 10 ноября 2010

У меня есть критический процесс, работающий в Java (1.6), с зарегистрированным хуком завершения работы.В некоторых случаях, когда у меня возникает проблема с OOM (подробнее об этом ниже), процесс внезапно останавливается, я не получаю никаких журналов, мой перехват (Throable x) не перехватывает исключение.

Но крюк отключения работает.Поэтому, если бы был способ узнать, что процесс будет остановлен из-за какого-то неприятного OOM, я мог бы записать необходимую информацию перед выходом.

Есть ли способ сделать это?

О OOM : Не уверен, что является исключением, потому что, как я сказал, оно не попадает.Я знаю, что это OOM, потому что я запускаю процесс с

-XX:+HeapDumpOnOutOfMemoryError

и получаю файл дампа кучи.В других случаях возникает исключение, и это ava.lang.OutOfMemoryError: превышен лимит накладных расходов GC.Но не уверен, что это всегда так.

РЕДАКТИРОВАТЬ:

На случай, если неясно: Я не пытаюсь предотвратить ООМ, как это может произойтипо уважительным причинам в каком-то сценарии, я просто хочу убедиться, что это ясно в файлах журнала приложения

Мой вопрос : возможно ли узнать, что процесс выключаетсяиз-за OOM во время завершения работы?

Мне нужно сделать это программно и из того же процесса .

На данный момент лучший подход - это посмотреть, существует ли файл дампа кучи java_pid_pid из process_.hprof (я знаю pid) с недавней датой и вывести, что был OOM.Я думаю, я мог бы попробовать Runtime.getRuntime (). FreeMemory () и сообщить о проблеме, если доступная память очень мала, но не уверен, насколько это надежно, возможно, когда процесс завершает работу, он уже освободил много памяти, подходвыше, я думаю, лучше всего.

Ответы [ 7 ]

3 голосов
/ 10 ноября 2010

OOM сложно, потому что если JVM не хватает памяти, он может не запустить код обработки исключений из-за нового OOM.

Попробуйте установить обработчик необработанных исключений по умолчанию . Он поймает все неисследованные исключения.

2 голосов
/ 10 ноября 2010

Возможно, вы захотите взглянуть на параметр -XX:OnOutOfMemoryError="cmd_with_pid_arg %p" (строка команды похожа на -XX:OnError).

2 голосов
/ 10 ноября 2010

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

Возможно, размещение вашего приложения в качестве Unix deamon или службы Windows будет болееуместно.

Но как насчет исследования утечки памяти с помощью инструментов профилирования?

jvisualvm - хороший вариант

1 голос
/ 10 ноября 2010

Используйте инструменты мониторинга, такие как jvisualvm или jconsole .

0 голосов
/ 10 ноября 2010

Опять же, использование jvisualvm (JDK 6, в папке bin), как предлагают другие или другие инструменты профилирования, является лучшим способом решения проблемы, а не ее решения, но при условии, что вы будете отдельно исследовать причины OOM и попытатьсяискоренить их, я хотел бы рассмотреть следующий POC, (см. также ответ Alois)

Как насчет запуска процесса Java, который обернет вызов процесса выброса OOM?результат отправляется в выходной поток вызываемого процесса, и посмотрите, есть ли согласованный код выхода / трассировка стека, которые вы можете использовать для идентификации OOM

Я уверен, что есть и другие подходы, но, похоже, этомне нравится хорошая, программная отправная точка

0 голосов
/ 10 ноября 2010

Вы должны решить проблему, а не пытаться ее компенсировать.

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

Что касается конкретной ошибки, которую вы получаете, посмотрите на этот SO вопрос: Ошибка java.lang.OutOfMemoryError: превышен лимит накладных расходов GC - похоже, самым простым решением будет увеличение размера кучи.

0 голосов
/ 10 ноября 2010

Вы можете (технически) перехватить OutOfMemoryErrors, но не уверены, что сможете выполнить код в блоке перехвата, если не осталось памяти.Стоит попробовать (1) перехватить OOM, (2) запустить сборку мусора (System.gc()) и попытаться записать что-нибудь в журнал или консоль.Нет гарантии, но это ничего не сломает.

...