Как сделать выход JVM в ЛЮБОМ исключении OutOfMemoryException, даже когда его пытаются поймать плохие люди? - PullRequest
21 голосов
/ 06 октября 2010

OOME относится к классу ошибок, которые обычно не следует исправлять. Но если оно скрыто в потоке или кто-то его ловит, приложение может перейти в состояние, из которого оно не выходит, но бесполезно. Любые предложения о том, как предотвратить это, даже несмотря на использование библиотек, которые могут глупо пытаться поймать Throwable или Error / OOME? (т.е. у вас нет прямого доступа для изменения исходного кода)

Ответы [ 9 ]

34 голосов
/ 07 октября 2010

Решение:

-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"

Определение: запускать пользовательские команды при первом возникновении ошибки OutOfMemoryError. (Введено в 1.4.2 обновление 12, 6)

См. http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

Пример, который убивает запущенный процесс:

-XX:OnOutOfMemoryError="kill -9 %p"
8 голосов
/ 06 октября 2010

Если какой-то фрагмент кода в JVM вашего приложения решит, что он хочет попытаться перехватить OOME и попытаться восстановить его, вы (к сожалению) ничего не сможете сделать, чтобы остановить его ... кроме героев AOP, которые, вероятно,непрактично и, безусловно, отрицательно сказывается на производительности и ремонтопригодности вашего приложения.Кроме того, лучшее, что вы можете сделать, это отключить JVM с помощью хука OnOutOfMemoryError.Смотрите ответ выше: https://stackoverflow.com/a/3878199/139985/

По сути, вы должны доверять другим разработчикам, чтобы они не делали глупостей.Другие глупые вещи, от которых вы, вероятно, не должны пытаться защищаться, включают:

  • вызов System.exit() в глубине библиотечного метода,
  • вызов Thread.stop() и друзей,
  • утечка открытых потоков, соединения с базой данных и т. Д.,
  • порождение большого количества потоков,
  • случайное сжатие (т.е. перехват и игнорирование), исключение
  • и т. Д.

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

Если проблема связана со сторонним поставщикомкод, сообщите об этом как ОШИБКА (что, вероятно, есть), и, если они не согласны, начните искать альтернативы.


Для тех, кто этого еще не знает, есть ряд причин, почемуЭто плохая идея, чтобы попытаться восстановиться после OOME:

  1. Возможно, OOME было выброшено, когда текущий поток находился в процессе обновления какой-то важной структуры данных.В общем случае код, который перехватывает этот OOME, не может этого знать, и если он пытается «восстановить», существует риск, что приложение продолжит работу с поврежденной структурой данных.

  2. Если приложение является многопоточным, существует вероятность того, что OOME могли бы быть брошены и в другие потоки, что затрудняет восстановление.

  3. Даже если приложение может восстановиться безоставляя структуры данных в несогласованном состоянии, восстановление может привести к тому, что приложение будет зависать еще несколько секунд, а затем снова OOME.

  4. Если вы не установите соответствующие параметры JVM, JVMэто почти исчерпало память имеет тенденцию тратить много времени на сбор мусора в тщетной попытке продолжать делать.Попытка восстановления из OOMEs, вероятно, продлит агонию.

Восстановление из OOME ничего не делает для устранения основной причины, которая обычно является утечкой памяти, плохо спроектированной (то есть расточительной памяти)) структура данных и / или запуск приложения с кучей, которая слишком мала.

2 голосов
/ 06 октября 2010
  1. edit OutOfMemoryError.java, добавьте System.exit() в его конструкторы.

  2. скомпилируйте его.(интересно, что javac не волнует, что он в пакете java.lang)

  3. добавьте класс в JRE rt.jar

  4. , теперь jvm будет использоватьэтот новый класс.(зло смеется)

Это возможность, о которой вы, возможно, захотите знать.Хорошая ли это идея или даже законная, это другой вопрос.

1 голос
/ 06 октября 2010

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

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

0 голосов
/ 06 октября 2010

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

Я не использовал его сам, но можно было бы отключить его таким образом, когда оставшееся количество памяти уменьшится, установив порог выделения и вызвав System.exit (), когда вы получите уведомление.

0 голосов
/ 06 октября 2010

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

Пожалуйста, скажите мне, что это не разумно.

0 голосов
/ 06 октября 2010

Вы можете запустить вашу Java-программу, используя Java Service Wrapper с Фильтром обнаружения OutOfMemory . Однако это предполагает, что «плохие люди» достаточно хороши, чтобы записать ошибку:)

0 голосов
/ 06 октября 2010

Как насчет того, чтобы поймать OOME в своем коде и System.exit()?

0 голосов
/ 06 октября 2010

Единственное, о чем я могу думать, это использовать AOP, чтобы обернуть каждый метод (будьте осторожны, чтобы исключить java. *) С помощью try-catch для OOME, и если это так, зарегистрируйте что-нибудь и вызовите System.exit () в блоке catch.

Не решение, которое я бы назвал элегантным ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...