Питання 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. Що таке витік пам’яті і як його виявити]]