Как сделать JVM-выход ЛЮБОЙ OutOfMemoryException, даже когда плохие люди пытаются его поймать

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

Ответ 1

Решение:

-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"

Ответ 2

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

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

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

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

Если проблема связана с сторонним кодом, сообщите об этом как о BUG (который, вероятно, есть), и если они не согласны, начните искать альтернативы.


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

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

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

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

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

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

Ответ 3

  • изменить OutOfMemoryError.java, добавить System.exit() в его конструкторах.

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

  • добавить класс в JRE rt.jar

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

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

Ответ 4

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

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

Ответ 5

Если вам все равно, как выйдет система, пока она завершает работу, может ли работать с переключателем -XX:+HeapDumpOnOutOfMemoryError JVM в команде запуска script/?

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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