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 createdThread 2022 createdThread 2023 createdException 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 spaceException 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_ . |