Отлов java.lang.OutOfMemoryError?

102

Документация для java.lang.Errorговорит:

Ошибка - это подкласс Throwable, который указывает на серьезные проблемы, которые разумное приложение не должно пытаться уловить.

Но поскольку java.lang.Errorэто подкласс java.lang.Throwable, я могу поймать этот тип Throwable.

Я понимаю, почему ловить такое исключение - не лучшая идея. Насколько я понимаю, если мы решим его поймать, обработчик catch не должен выделять память сам по себе. В противном случае OutOfMemoryErrorбудет брошен еще раз.

Итак, мой вопрос:

  1. Существуют ли какие-либо реальные сценарии, когда ловля java.lang.OutOfMemoryErrorможет быть хорошей идеей?
  2. Если мы решим поймать java.lang.OutOfMemoryError, как мы можем убедиться, что обработчик catch не выделяет память сам по себе (какие-либо инструменты или лучшие практики)?
Денис Баженов
источник
Что касается вашего первого вопроса, я добавлю, что я поймаю OutOfMemoryError, чтобы (по крайней мере, попытаться) уведомить пользователя о проблеме. Раньше ошибка не обнаруживалась предложением catch (Exception e), и пользователю не отображалась обратная связь.
Хосеп Родригес Лопес
1
Есть особые случаи, например, выделение гигантского массива, когда можно поймать ошибку OOM вокруг этой операции и достаточно хорошо восстановить. Но размещение команды try / catch вокруг большого фрагмента кода и попытка его полного восстановления и продолжения, вероятно, является плохой идеей.
Hot Licks
См. Также stackoverflow.com/questions/14376924/…
Raedwald

Ответы:

86

Я согласен и не согласен с большинством приведенных здесь ответов.

Существует ряд сценариев, в которых вы, возможно, захотите уловить, 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) {}везде накидывать одеяло или такую ​​ерунду.

Крис
источник
Согласитесь, выложу свой эксперимент по новому ответу.
Мистер Смит,
4
«вы никогда не можете быть на 100% уверены, что JVM находится в исправном состоянии»: потому что это OutOfMemoryErrorмогло быть выброшено из точки, которая поместила вашу программу в несогласованное состояние, потому что она может быть выброшена в любое время. См stackoverflow.com/questions/8728866/...
Raedwald
В OpenJdk1.7.0_40 я не получаю никаких ошибок или исключений при запуске этого кода. Даже я поменял MEGABYTE на GIGABYTE (1024 * 1024 * 1024). Это потому, что оптимизатор удаляет переменную byte [] bytes, поскольку она не используется в остальной части кода?
RoboAlex
«Есть несколько сценариев, в которых вы можете захотеть поймать OutOfMemoryError» по сравнению с «Есть только одна веская причина поймать OutOfMemoryError» . Прими решение!!!
Stephen C
3
Реальный сценарий, когда вы МОЖЕТЕ захотеть поймать ошибку OutOfMemory: когда она вызвана попыткой выделить массив с более чем 2G элементами. Название ошибки в этом случае немного неверно, но это все еще OOM.
Чарльз Рот
31

Вы можете восстановить из нее:

package com.stackoverflow.q2679330;

public class Test {

    public static void main(String... args) {
        int size = Integer.MAX_VALUE;
        int factor = 10;

        while (true) {
            try {
                System.out.println("Trying to allocate " + size + " bytes");
                byte[] bytes = new byte[size];
                System.out.println("Succeed!");
                break;
            } catch (OutOfMemoryError e) {
                System.out.println("OOME .. Trying again with 10x less");
                size /= factor;
            }
        }
    }

}

Но есть ли в этом смысл? Что еще ты хотел бы сделать? Зачем изначально выделять столько памяти? Меньше памяти тоже нормально? Почему ты все равно не используешь его? Или, если это невозможно, почему бы просто не дать JVM с самого начала больше памяти?

Вернуться к вашим вопросам:

1: есть ли какие-либо сценарии реального слова при отлове java.lang.OutOfMemoryError может быть хорошей идеей?

Ничего не приходит в голову.

2: если мы перехватываем java.lang.OutOfMemoryError, как мы можем быть уверены, что обработчик перехвата не выделяет память сам по себе (какие-либо инструменты или лучшие практики)?

Зависит от того, что вызвало ошибку OOME. Если это заявлено вне tryблока и происходило поэтапно, то ваши шансы невелики. Вы можете заранее зарезервировать место в памяти:

private static byte[] reserve = new byte[1024 * 1024]; // Reserves 1MB.

а затем установите его в ноль во время OOME:

} catch (OutOfMemoryException e) {
     reserve = new byte[0];
     // Ha! 1MB free!
}

Конечно, в этом нет никакого смысла;) Просто дайте JVM достаточно памяти, как того требует ваше приложение. При необходимости запустите профилировщик.

BalusC
источник
1
Однако даже резервирование места не гарантирует рабочего решения. Это место может быть занято и другим потоком;)
Wolph
@Wolph: Тогда дайте JVM больше памяти! О_о Все со всем в этом действительно нет смысла;)
BalusC
2
Первый фрагмент работает, потому что объект, вызвавший ошибку, является одним БОЛЬШИМ объектом (массивом). Когда достигается предложение catch, оно было собрано JVM, требующей много памяти. Если вы использовали тот же объект вне блока try, или в другом потоке, или в том же catch, JVM не собирает его, что делает невозможным создание нового отдельного объекта любого типа. второй фрагмент, например, может не работать.
Мистер Смит,
3
почему бы просто не установить его null?
Pacerier 03
1
@MisterSmith Ваш комментарий не имеет смысла. Большого объекта не существует. Он не был выделен изначально: он запускал OOM, поэтому GC определенно не нужен.
Marquis of Lorne
16

В общем, пытаться поймать OOM и восстановиться после него - плохая идея.

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

  2. Даже если вы успешно восстановитесь, ваша JVM может все еще страдать от нехватки памяти, и в результате ваше приложение будет работать ужасно.

Лучшее, что можно сделать с OOME, - это позволить JVM умереть.

(Предполагается, что JVM действительно умирает. Например, OOM в потоке сервлета Tomcat не уничтожают JVM, и это приводит к тому, что Tomcat переходит в кататоническое состояние, когда он не отвечает ни на какие запросы ... даже запросы на начать сначала.)

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

Я не говорю, что ловить OOM - плохая идея. Проблемы возникают, когда вы пытаетесь выйти из OOME намеренно или по недосмотру. Всякий раз, когда вы ловите OOM (напрямую или как подтип Error или Throwable), вы должны либо повторно выбросить его, либо обеспечить выход из приложения / JVM.

Кроме того: это говорит о том, что для максимальной устойчивости перед лицом OOM приложение должно использовать Thread.setDefaultUncaughtExceptionHandler () для установки обработчика, который приведет к завершению приложения в случае OOME, независимо от того, в каком потоке запущено OOME. Мне было бы интересно узнать мнение по этому поводу ...

Единственный другой сценарий - это когда вы точно знаете , что OOM не привел к какому-либо сопутствующему ущербу; т.е. вы знаете:

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

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

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

Стивен С
источник
Да, я согласен с тобой. В общем, идея плохая. Но почему тогда у меня есть возможность его поймать? :)
Денис Баженов
@dotsid - 1) потому что есть случаи, когда вы должны его поймать, и 2) потому что невозможность поймать OOM будет иметь негативное влияние на язык и / или другие части среды выполнения Java.
Stephen C
1
Вы говорите: «Потому что есть случаи, когда надо ловить». Так что это было частью моего первоначального вопроса. Что те случаи , когда вы хотите поймать OOME?
Денис Баженов
1
@dotsid - см. мой отредактированный ответ. Единственный случай, который я могу придумать для перехвата OOM, - это когда вам нужно сделать это, чтобы заставить многопоточное приложение выйти в случае OOM. Возможно, вы захотите сделать это для всех подтипов Error.
Stephen C
1
Дело не только в том, чтобы поймать OOME. От них тоже нужно оправиться. Как поток восстанавливается, если он должен был (скажем) уведомить другой поток ... но получил OOME? Конечно, JVM не умрет. Но приложение, скорее всего, перестанет работать из-за зависания потоков в ожидании уведомлений от потоков, которые перезапустились из-за перехвата OOME.
Stephen C
14

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

(Поскольку происходит сбой при выделении одного массива нескольких гигабайт, JVM по-прежнему работает нормально после обнаружения ошибки, а памяти достаточно для обработки других элементов.)

Майкл Кун
источник
Итак, у вас есть код вроде byte[] bytes = new byte[length]? Почему бы просто не проверить sizeна более раннем этапе?
Raedwald
1
Потому что то же самое sizeбудет и с большим объемом памяти. Я использую исключение, потому что в большинстве случаев все будет хорошо.
Майкл Кун
10

Определенно есть сценарии, в которых имеет смысл поймать OOME. IDEA улавливает их и открывает диалоговое окно, позволяющее изменить настройки загрузочной памяти (а затем закрывается, когда вы закончите). Сервер приложений может их поймать и сообщить. Ключом к этому является выполнение этого на высоком уровне отправки, чтобы у вас был разумный шанс освободить кучу ресурсов в точке, где вы перехватываете исключение.

Помимо сценария IDEA, приведенного выше, в общем случае перехват должен быть Throwable, а не только OOM, и должен выполняться в контексте, где, по крайней мере, поток будет вскоре завершен.

Конечно, в большинстве случаев память не хватает, и ситуацию невозможно исправить, но есть способы, которыми это имеет смысл.

Ишай
источник
8

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

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

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
bitmapOptions.inSampleSize = 1;
boolean imageSet = false;
while (!imageSet) {
  try {
    image = BitmapFactory.decodeFile(filePath, bitmapOptions);
    imageView.setImageBitmap(image); 
    imageSet = true;
  }
  catch (OutOfMemoryError e) {
    bitmapOptions.inSampleSize *= 2;
  }
}

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

Мария
источник
1
Другой вариант - вычислить, насколько большие растровые изображения вы можете обработать, вместо того, чтобы пытаться и терпеть неудачу. «Исключения надо использовать в исключительных случаях», - мне кажется, кто-то сказал. Но я скажу, ваше решение кажется самым простым выходом, возможно, не лучшим, но, вероятно, самым простым.
jontejj 07
Это зависит от кодека. Представьте, что bmp размером 10 МБ, вероятно, приведет к куче чуть больше 10 МБ, в то время как JPEG размером 10 МБ будет «взорваться». То же самое в моем случае, когда я хочу проанализировать XML, который может сильно различаться в зависимости от сложности контента
Дэниел Алдер
5

Да, настоящий вопрос в том, «что вы собираетесь делать в обработчике исключений?» Практически для всего полезного вы выделяете больше памяти. Если вы хотите выполнить некоторую диагностическую работу при возникновении OutOfMemoryError, вы можете использовать -XX:OnOutOfMemoryError=<cmd>ловушку, предоставляемую виртуальной машиной HotSpot. Он выполнит ваши команды при возникновении OutOfMemoryError, и вы сможете делать что-нибудь полезное вне кучи Java. Вы действительно хотите, чтобы приложение не исчерпало память, поэтому первый шаг - выяснить, почему это происходит. Затем вы можете при необходимости увеличить размер кучи MaxPermSize. Вот еще несколько полезных ловушек HotSpot:

-XX:+PrintCommandLineFlags
-XX:+PrintConcurrentLocks
-XX:+PrintClassHistogram

Смотрите полный список здесь

Роб Хейзер
источник
Это даже хуже, чем ты думаешь. Поскольку an OutOfMemeoryError может быть брошен в любой момент вашей программы (не только из newоператора), ваша программа будет в неопределенном состоянии, когда вы поймаете исключение.
Raedwald
5

У меня есть приложение, которое нужно восстанавливать после сбоев OutOfMemoryError, и в однопоточных программах оно всегда работает, но иногда не работает в многопоточных программах. Приложение представляет собой автоматизированный инструмент тестирования Java, который выполняет сгенерированные тестовые последовательности на максимально возможной глубине в тестовых классах. Теперь пользовательский интерфейс должен быть стабильным, но движку тестирования может не хватить памяти во время роста дерева тестовых случаев. Я справляюсь с этим с помощью следующей идиомы кода в тестовой машине:

логическое isOutOfMemory = false; // флаг, используемый для отчета
пытаться {
   SomeType largeVar;
   // Основной цикл, который выделяет все больше и больше для largeVar
   // может завершиться ОК или вызвать OutOfMemoryError
}
catch (OutOfMemoryError ex) {
   // largeVar теперь вне области видимости, поэтому это мусор
   System.gc (); // очищаем данные largeVar
   isOutOfMemory = true; // флаг доступен для использования
}
// программа проверяет флаг, чтобы сообщить о восстановлении

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

Например, у меня происходило OOME, когда кадры анимированного GIF в моем пользовательском интерфейсе циклически перебирались проприетарным потоком, который создается за кулисами классом Swing, который находится вне моего контроля. Я думал, что выделил все необходимые ресурсы заранее, но очевидно, что аниматор выделяет память каждый раз, когда выбирает следующее изображение. Если у кого-то есть идея о том, как обрабатывать OOME, поднятые в любом потоке, я хотел бы услышать.

Тони Саймонс
источник
В однопоточном приложении, если вы больше не используете некоторые из проблемных новых объектов, создание которых вызвало ошибку, они могут быть собраны в предложении catch. Однако, если JVM обнаруживает, что объект может быть использован позже, он не может быть собран, и приложение взрывается. Смотрите мой ответ в этой теме.
Мистер Смит,
4

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

Пример: в моей JVM эта программа выполняется до завершения:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
        }
        System.out.println("Test finished");
    }  
}

Однако простое добавление единственной строчки в уловке покажет вам, о чем я говорю:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
            System.out.println("size:" +ll.size());
        }
        System.out.println("Test finished");
    }
}

Первая программа работает нормально, потому что при достижении улова JVM обнаруживает, что список больше не будет использоваться (это обнаружение также может быть оптимизацией, сделанной во время компиляции). Итак, когда мы достигаем оператора печати, память кучи была освобождена почти полностью, так что теперь у нас есть большой запас маневра для продолжения. Это лучший случай.

Однако, если код организован так, как если бы список llиспользовался после того, как OOME был пойман, JVM не сможет его собрать. Это происходит во втором фрагменте. OOME, запускаемый новым созданием Long, улавливается, но вскоре мы создаем новый объект (String в System.out,printlnстроке), а куча почти заполнена, поэтому создается новый OOME. Это наихудший сценарий: мы пытались создать новый объект, у нас ничего не вышло, мы перехватили OOME, да, но теперь первая инструкция, требующая новой памяти кучи (например, создание нового объекта), вызовет новый OOME. Подумайте об этом, что еще мы можем сделать в этот момент, когда осталось так мало памяти? Наверное, просто ухожу. Отсюда и бесполезное.

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

Я использую 32-битную JVM для Windows x86 (JRE6). Память по умолчанию для каждого приложения Java составляет 64 МБ.

Мистер Смит
источник
Что, если я сделаю это ll=nullвнутри блока catch?
Naanavanalla
3

Единственная причина, по которой я могу думать о том, почему перехват ошибок OOM может заключаться в том, что у вас есть массивные структуры данных, которые вы больше не используете, и вы можете установить значение null и освободить некоторую память. Но (1) это означает, что вы тратите память и вам следует исправить свой код, а не просто хромать после OOME, и (2) что бы вы сделали, даже если вы его поймали? OOM может произойти в любое время, потенциально оставив все наполовину готовым.

Чао
источник
3

По вопросу 2 я уже вижу решение, которое я бы предложил, от BalusC.

  1. Есть ли какие-либо реальные сценарии слов при отлове java.lang.OutOfMemoryError может быть хорошей идеей?

Думаю, я только что наткнулся на хороший пример. Когда приложение awt отправляет сообщения, на stderr отображается неотловленная ошибка OutOfMemoryError, и обработка текущего сообщения останавливается. Но приложение продолжает работать! Пользователь по-прежнему может выполнять другие команды, не зная о серьезных проблемах, происходящих за сценой. Особенно, когда он не может или не соблюдает стандартную ошибку. Так что перехват исключения oom и обеспечение (или, по крайней мере, предложение) перезапуска приложения - это то, что нужно.

Ярекчек
источник
3

У меня просто есть сценарий, в котором обнаружение OutOfMemoryError имеет смысл и, похоже, работает.

Сценарий: в приложении для Android я хочу отображать несколько растровых изображений с максимально возможным разрешением, и я хочу иметь возможность плавно их масштабировать.

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

В этой ситуации при чтении растрового изображения может возникнуть ошибка OutOfMemoryError. Здесь помогает, если я поймаю это, а затем продолжу с более низким разрешением.

Йорг Айсфельд
источник
0
  1. Зависит от того, как вы определяете «хорошо». Мы делаем это в нашем веб-приложении с ошибками, и оно работает большую часть времени (к счастью, сейчасOutOfMemory этого не происходит из-за несвязанного исправления). Однако, даже если вы поймаете это, он все равно может сломать какой-то важный код: если у вас несколько потоков, выделение памяти может завершиться ошибкой в ​​любом из них. Таким образом, в зависимости от вашего приложения вероятность необратимого выхода из строя составляет 10-90%.
  2. Насколько я понимаю, тяжелая раскрутка стека по пути сделает так много ссылок недействительными и, таким образом, освободит столько памяти, что вам не стоит беспокоиться об этом.

РЕДАКТИРОВАТЬ: Я предлагаю вам попробовать. Скажем, напишите программу, которая рекурсивно вызывает функцию, которая постепенно выделяет больше памяти. Поймайте OutOfMemoryErrorи посмотрите, сможете ли вы осмысленно продолжить с этого момента. По моему опыту, вы сможете это сделать, хотя в моем случае это произошло на сервере WebLogic, так что здесь могла быть какая-то черная магия.

удваивать
источник
-1

Вы можете поймать что угодно в Throwable, вообще говоря, вы должны ловить только подклассы Exception, исключая RuntimeException (хотя большая часть разработчиков также ловит RuntimeException ... но это никогда не было намерением разработчиков языка).

Если бы вы поймали OutOfMemoryError, что бы вы сделали? На виртуальной машине не хватает памяти, все, что вы можете сделать, это выйти. Вы, вероятно, даже не можете открыть диалоговое окно, чтобы сказать им, что у вас не хватает памяти, поскольку это займет память :-)

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

Что нужно сделать, это выяснить, почему вам не хватает памяти (используйте профилировщик, такой как в NetBeans), и убедитесь, что у вас нет утечек памяти. Если у вас нет утечек памяти, увеличьте объем памяти, который вы выделяете виртуальной машине.

Тофу пиво
источник
7
Заблуждение, которое увековечивает ваш пост, заключается в том, что OOM указывает, что JVM не хватает памяти. Вместо этого это фактически указывает на то, что JVM не смогла выделить всю память, на которую она была указана. То есть, если JVM имеет 10 Байт пространства, и вы «обновляете» объект 100 Байт, он выйдет из строя, но вы можете развернуться и «обновить» объект 5 Б и все будет в порядке.
Тим Бендер
1
И если мне нужно было только 5B, почему я прошу 10B? Если вы делаете распределение на основе проб и ошибок, вы делаете это неправильно.
TofuBeer
2
Думаю, Тим имел в виду, что вы все равно можете выполнять некоторую работу даже в ситуации OutOfMemory. Например, может быть достаточно памяти, чтобы открыть диалог.
Стивен Эйлерт