Вопрос 20 · Раздел 3

Какие типы OutOfMemoryError существуют?

4. MaxDirectMemorySize — контроль NIO 5. Мониторьте dmesg для OOM Killer 6. jcmd VM.metaspace для анализа Metaspace

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

OutOfMemoryError бывает разных типов — каждый указывает на свою проблему:

Тип Что значит
Java heap space Heap переполнен
GC overhead limit exceeded GC работает постоянно
Metaspace Метаданные классов переполнены
Direct buffer memory Память вне Heap (NIO)
Unable to create new native thread Лимит потоков ОС

🟡 Middle Level

Java heap space

Причина: утечка или маленький -Xmx
Решение: 
  1. -XX:+HeapDumpOnOutOfMemoryError
  2. Анализ в MAT
  3. Найти утечку или увеличить -Xmx

GC overhead limit exceeded

98% времени на GC, < 2% освобождается
→ Приложение "зависло" в бесконечном цикле Full GC

Решение:
  - Увеличить Heap
  - Найти утечку
  - Отключить: -XX:-UseGCOverheadLimit (не рекомендуется!)

Metaspace

Метаданные классов переполнены
Причины:
  - Динамическая генерация (Spring, CGLIB)
  - Утечка ClassLoader-ов

Решение:
  -XX:MaxMetaspaceSize=512m
  jcmd <pid> VM.metaspace

Direct buffer memory

NIO память вне Heap
Причины: Netty, ByteBuffer.allocateDirect()

Решение:
  -XX:MaxDirectMemorySize=2g
  Проверить утечки в Netty

Unable to create new native thread

ОС не может создать поток
Причины:
  - ulimit -u достигнут
  - RAM для стеков (-Xss) закончилась

Решение:
  Уменьшить -Xmx (больше RAM для стеков)
  Проверить ulimit -u

🔴 Senior Level

Requested array size exceeds VM limit

Массив > Integer.MAX_VALUE элементов
→ Чаще всего указывает на ошибку в логике. Но бывают легитимные случаи: попытка загрузить большой файл в память целиком.

Compressed Class Space

Compressed Class Space — часть Metaspace для сжатых указателей на классы (4 байта вместо 8).
Лимит: -XX:CompressedClassSpaceSize (1 ГБ по умолчанию). Переполнение → OOME, даже если Metaspace свободен.

Map failed (Memory Mapped Files)

MappedByteBuffer.map() → ошибка
  → vm.max_map_count достигнут
  → Нет виртуальной памяти для маппинга
  
Решение: sysctl -w vm.max_map_count=262144

Linux OOM Killer

НЕ Java ошибка!
  → Контейнер: лимит < RSS
  → ОС убивает процесс через SIGKILL
  → Нет дампов, нет логов!
  
Диагностика:
  dmesg | grep -i oom
  → "Out of memory: Kill process"

Сводная таблица

Тип Куда смотреть Флаг
Heap Утечки в Heap HeapDumpOnOOM
Metaspace ClassLoader leaks VM.metaspace
Direct buffer Netty/NIO NMT
Native thread ulimit, -Xss ps -Hu
GC overhead Thrashing GC Logs

Best Practices

  1. HeapDumpOnOutOfMemoryError — обязательно
  2. NMT=detail для Native Memory
  3. MaxMetaspaceSize — лимит для контейнеров
  4. MaxDirectMemorySize — контроль NIO
  5. Мониторьте dmesg для OOM Killer
  6. jcmd VM.metaspace для анализа Metaspace

Резюме для Senior

  • Тип OOME = первая улика в расследовании
  • Heap space = утечки в Heap
  • Metaspace = ClassLoader leaks
  • Direct buffer = NIO утечки (вне Heap)
  • Native thread = лимиты ОС
  • OOM Killer = не Java ошибка (контейнеры)
  • NMT = диагностика Native Memory

🎯 Шпаргалка для интервью

Обязательно знать:

  • Java heap space — Heap переполнен; решение: HeapDumpOnOOM + MAT анализ + найти утечку или увеличить -Xmx
  • GC overhead limit exceeded — 98% времени на GC, < 2% освобождается; бесконечный цикл Full GC
  • Metaspace — метаданные классов переполнены; причины: динамическая генерация (Spring, CGLIB), утечка ClassLoader
  • Direct buffer memory — NIO память вне Heap; Netty, ByteBuffer.allocateDirect(); решение: MaxDirectMemorySize
  • Unable to create new native thread — ulimit -u достигнут или RAM для стеков (-Xss) закончилась
  • Requested array size exceeds VM limit — массив > Integer.MAX_VALUE; чаще ошибка в логике
  • Linux OOM Killer — НЕ Java ошибка! Контейнер: лимит < RSS → ОС убивает через SIGKILL → нет дампов

Частые уточняющие вопросы:

  • Как отличить JVM OOME от OS OOM Killer? — JVM OOME: стек-трейс в логах; OOM Killer: dmesg | grep -i oom, процесс исчезает без логов
  • Что такое Compressed Class Space OOME? — Часть Metaspace для сжатых указателей на классы (1 ГБ лимит); переполнение → OOME, даже если Metaspace свободен
  • Почему «Requested array size exceeds VM limit» случается? — Попытка создать массив > Integer.MAX_VALUE элементов; часто баг (загрузка большого файла целиком)
  • Как диагностировать OOM Killer в Kubernetes?dmesg | grep -i oom; Pod terminated (OOMKilled); решение: увеличить лимит или уменьшить RSS

Красные флаги (НЕ говорить):

  • «Отключу -XX:-UseGCOverheadLimit и проблема решится» — это маскирует проблему; приложение всё равно упадёт с Heap space OOME
  • «OOM Killer — это баг Java» — это решение ОС; Java не контролирует лимиты контейнера
  • «Direct buffer memory = часть Heap» — DirectByteBuffer выделяет память ВНЕ Heap (-Xmx не влияет)

Связанные темы:

  • [[19. Что произойдёт при OutOfMemoryError]]
  • [[11. Что такое Metaspace (или PermGen)]]
  • [[6. Что такое утечка памяти в Java]]
  • [[18. Что такое параметры -Xms и -Xmx]]
  • [[21. Что такое memory leak и как его обнаружить]]