OutOfMemoryError
может быть OutOfMemoryError
при возникновении одного из следующих обстоятельств:
- JVM не хватает родной памяти
- Кучи Java не хватает памяти
- PermGen или Metaspace не хватает памяти
- JVM потратила слишком много времени, пытаясь собрать мусор
Основная причина OutOfMemoryError
обычно может быть вычтена из сообщения об ошибке. Давайте посмотрим на детали каждого из обстоятельств.
JVM не хватает родной памяти
В основном это означает, что объем памяти, выделенной для JVM, исчерпан. Максимальный размер процесса для 32-разрядной JVM составляет примерно 3,5–4 ГБ. Если он превышен, OutOfMemoryError
будет брошен. Даже в 64-разрядной JVM, когда JVM запрашивает больше памяти, операционной системе может просто не хватать ее. Посмотрите на следующий фрагмент:
01
02
03
04
05
06
07
08
09
10
11
|
for ( int i = 0 ; true ; ++i) { new Thread() { public void run() { try { Thread.sleep( 1000000 ); } catch (InterruptedException e) { } } }.start(); System.out.println( "Thread" ; + i + "created" ); } |
На моем ноутбуке (64-битная Mac OS X 10.11.6 с Java 1.8.0_112) JVM аварийно завершает работу после создания 2023 потоков:
1
2
3
4
|
Thread 2021 created Thread 2022 created Thread 2023 created Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread |
Кучи Java не хватает памяти
Это довольно очевидно. Слишком много объектов выделено, поэтому они не помещаются в пространство кучи, настроенное для JVM. Увеличение размера кучи звучит как решение, но если оно вызвано утечкой памяти, оно просто OutOfMemoryError
. Сообщение об ошибке довольно ясно:
1
|
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space |
PermGen или Metaspace не хватает памяти
PermGen (Java 7 и более ранние версии) имеет ограниченный максимальный размер . Это означает, что если загружено слишком много классов, PermGen может заполниться, и OutOfMemoryError
будет брошен. Увеличение максимального размера PermGen должно помочь. Java 8 не имеет PermGen, но вместо этого Metaspace. По умолчанию он имеет неограниченный максимальный размер, поэтому до тех пор, пока вы не установите ограничение с MaxMetaspaceSize
флага MaxMetaspaceSize
, ошибка не должна возникать. Чтобы диагностировать OutOfMemoryError
вызванную PermGen или Metaspace, следует изучить сообщение об ошибке:
1
2
|
Exception in thread “main” java.lang.OutOfMemoryError: PermGen space Exception in thread “main” java.lang.OutOfMemoryError: Metaspace |
JVM потратила слишком много времени, пытаясь собрать мусор
Это самый OutOfMemoryError
— OutOfMemoryError
когда GC тратит слишком много времени на сбор мусора с слишком маленьким результатом, а дальнейшее выполнение приложения не имеет смысла. Другими словами, должны быть выполнены все следующие условия :
- Более 98% времени уходит в GC (98% является значением по умолчанию, оно может быть переопределено
GCTimeLimit=N
) - Менее 2% кучи восстанавливается во время полного GC (опять же, 2% является значением по умолчанию, оно может быть переопределено
GCHeapFreeLimit=N
) - Оба условия, упомянутые выше, выполняются в течение пяти последовательных полных циклов ГХ
- Флаг
UseGCOverheadLimit
не отключен (значение по умолчанию — true)
Запуск полного GC означает, что JVM не хватает памяти в любом случае. Если 98% времени тратится на освобождение только 2% кучи, то это означает, что ЦП почти полностью занят GC и практически никакая логика приложения не может быть выполнена. Вот почему имеет смысл отказаться и выбросить OutOfMemoryError
со следующим сообщением:
1
|
Exception in thread “main” java.lang.OutOfMemoryError: GC overhead limit exceeded |
Ссылка: | Что вызывает OutOfMemoryError? от нашего партнера JCG Гжегожа Мирека в > блоге исполнителя code_ . |