Які типи OutOfMemoryError існують?
4. MaxDirectMemorySize — контроль NIO 5. Моніторьте dmesg для OOM Killer 6. jcmd VM.metaspace для аналізу Metaspace
🟢 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
- HeapDumpOnOutOfMemoryError — обов’язково
- NMT=detail для Native Memory
- MaxMetaspaceSize — ліміт для контейнерів
- MaxDirectMemorySize — контроль NIO
- Моніторьте dmesg для OOM Killer
- 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 аналіз + знайти витік або збільшити -XmxGC overhead limit exceeded— 98% часу на GC, < 2% звільняється; нескінченний цикл Full GCMetaspace— метадані класів переповнені; причини: динамічна генерація (Spring, CGLIB), витік ClassLoaderDirect buffer memory— NIO пам’ять поза Heap; Netty, ByteBuffer.allocateDirect(); рішення: MaxDirectMemorySizeUnable 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. Що таке витік пам’яті і як його виявити]]