Що таке Metaspace (або PermGen)?
4. Кешуйте проксі та скрипти 5. TraceClassLoading для налагодження
🟢 Junior Level
Metaspace — область пам’яті (поза Heap), де Java зберігає метадані класів.
Метадані включають: ім’я класу, імена та сигнатури методів, поля, анотації, constant pool, vtable/itable (таблиці віртуальних методів).
Проста аналогія: Якщо Heap — це гардероб з одягом, то Metaspace — це каталог з описами одягу.
Що зберігається:
- Інформація про класи
- Методи та їх байт-код
- Constant Pool
PermGen → Metaspace (Java 8):
- PermGen: фіксований розмір всередині Heap → OOM
- Metaspace: OOM трапляється рідше, але все ще поширений при динамічній генерації класів (Spring, Hibernate, Groovy, CGLIB)
🟡 Middle Level
PermGen vs Metaspace
| Характеристика | PermGen | Metaspace |
|---|---|---|
| Розташування | Всередині Heap | Native Memory |
| Розмір | Фіксований | Динамічний |
| OOM | Частий | Рідкий |
Що викликає ріст Metaspace
1. Багато класів у додатку
2. Динамічна генерація (Spring проксі, CGLIB)
3. Витік ClassLoader-ів
4. Скриптові рушії (Groovy, JavaScript)
Налаштування
-XX:MetaspaceSize=256m # Поріг для першого GC
-XX:MaxMetaspaceSize=512m # Максимум (обов'язково!)
ClassLoader Leaks
Класи живі, поки живий їх ClassLoader
→ Якщо ClassLoader не GC → всі класи залишаються
Причини:
- ThreadLocal зберігає об'єкт з ClassLoader
- Static поле посилається на клас додатку
- JDBC driver у DriverManager
🔴 Senior Level
Compressed Class Space
Окрема область у Metaspace для Klass структур
→ За замовчуванням 1 ГБ
→ -XX:CompressedClassSpaceSize для зміни
Klass = C++ дзеркало Java-класу
→ InstanceKlass (vtable, itable)
→ Method Metadata
→ Constant Pool
High-Water Mark механізм
1. Metaspace росте → досягає MetaspaceSize
2. Full GC → спроба вивантажити ClassLoader-и
3. Якщо мало → розширюється і піднімається поріг
4. Повторюється
Проблема: серія Full GC на старті додатку
Рішення: MetaspaceSize = типовий рівень після прогріву
Elastic Metaspace (Java 16+)
JEP 387: покращене повернення пам'яті ОС
→ Раніше: великі Chunks → фрагментація
→ Тепер: дрібні блоки → агресивне повернення
Діагностика
jcmd <pid> VM.metaspace # Детальний звіт
jstat -gc <pid> 1000 # MU колонка
-Xlog:class+load=info # Завантаження класів
Best Practices
- MaxMetaspaceSize — обов’язковий у Docker. Не ставте занадто близько до реального споживання — це викличе часті Full GC. Запас мінімум 30-50%.
- MetaspaceSize = споживання після прогріву
- Моніторте витоки ClassLoader
- Кешуйте проксі та скрипти
- TraceClassLoading для налагодження
Резюме для Senior
- Metaspace = native memory для метаданих класів
- High-Water Mark = динамічне розширення
- ClassLoader Leaks = головна причина OOM
- Compressed Class Space = 1 ГБ ліміт
- Elastic Metaspace (Java 16+) = краще повернення пам’яті
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- Metaspace (Java 8+) зберігає метадані класів: ім’я класу, методи, поля, анотації, constant pool, vtable/itable
- PermGen (до Java 7): всередині Heap, фіксований розмір → часті OOM; Metaspace: native memory, динамічне зростання
- ClassLoader Leak — головна причина OOM Metaspace; класи живі, поки живий їх ClassLoader
- High-Water Mark: Metaspace росте → Full GC → якщо мало вивантажено → розширення → серія Full GC на старті
-XX:MaxMetaspaceSizeобов’язковий у Docker;-XX:MetaspaceSize= типове споживання після прогріву- Elastic Metaspace (Java 16+, JEP 387): дрібні блоки замість великих Chunks → агресивне повернення пам’яті ОС
- Compressed Class Space: окрема область ~1 ГБ для Klass структур (C++ дзеркал Java-класів)
Часті уточнюючі запитання:
- Що викликає ріст Metaspace? — Динамічна генерація класів (Spring/CGLIB/Hibernate), Groovy/JavaScript скрипти, витік ClassLoader
- Чому MetaspaceSize викликає Full GC на старті? — При досягненні порогу JVM запускає Full GC для вивантаження ClassLoader; якщо поріг занижений — серія Full GC
- Як діагностувати витік ClassLoader? —
jcmd <pid> VM.metaspace,-Xlog:class+load=info, порівняти завантаження/вивантаження класів - Чому MaxMetaspaceSize не можна ставити впритул? — Запас мінімум 30-50% від реального споживання; інакше часті Full GC
Червоні прапорці (НЕ говорити):
- «Metaspace всередині Heap» — Metaspace в native memory (поза Heap)
- «PermGen та Metaspace — одне й те саме» — PermGen фіксований всередині Heap, Metaspace динамічний в native memory
- «Metaspace OOM неможливий» — трапляється при динамічній генерації класів та ClassLoader leaks
Пов’язані теми:
- [[7. Як може статися витік пам’яті в Java]]
- [[8. Що таке покоління в GC (young, old, metaspace)]]
- [[20. Які типи OutOfMemoryError існують]]
- [[6. Що таке витік пам’яті в Java]]
- [[2. Що зберігається в Heap]]