Я согласен и не согласен с большинством ответов здесь.
Существует ряд сценариев, в которых вы можете захотеть поймать OutOfMemoryError
, и, по моему опыту (в JVM для Windows и Solaris), очень редко OutOfMemoryError
является сигналом смерти для JVM.
Есть только одна веская причина поймать OutOfMemoryError
, а именно: аккуратно закрыть, аккуратно высвободить ресурсы и записать причину сбоя как можно лучше (если это все еще возможно).
Как правило, OutOfMemoryError
происходит из-за выделения памяти блока, которое не может быть удовлетворено оставшимися ресурсами кучи.
Когда выбрасывается Error
, куча содержит то же количество выделенных объектов, что и до неудачного выделения, и теперь настало время отбросить ссылки на объекты времени выполнения, чтобы освободить еще больше памяти, которая может потребоваться для очистки. В этих случаях возможно даже продолжение, но это определенно будет плохой идеей, поскольку вы никогда не можете быть на 100% уверены, что JVM находится в исправимом состоянии.
Демонстрация того, что OutOfMemoryError
не означает, что JVM не хватает памяти в блоке catch:
private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
for (int i=1; i <= 100; i++) {
try {
byte[] bytes = new byte[MEGABYTE*500];
} catch (Exception e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
long maxMemory = heapUsage.getMax() / MEGABYTE;
long usedMemory = heapUsage.getUsed() / MEGABYTE;
System.out.println(i+ " : Memory Use :" + usedMemory + "M/" + maxMemory + "M");
}
}
}
Вывод этого кода:
1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M
Если выполняется что-то критическое, я обычно ловлю Error
, записываю его в syserr, затем записываю в журнал, используя мою платформу журналирования, затем продолжаю освобождать ресурсы и закрывать чистым способом. Что самое худшее, что может случиться? В любом случае JVM умирает (или уже мертва), и если поймать Error
, то, по крайней мере, есть шанс на очистку.
Предостережение заключается в том, что вы должны нацеливаться на обнаружение этих типов ошибок только в местах, где возможна очистка. Не покрывайте catch(Throwable t) {}
всюду или ерундой как этот.