Питання 11 · Розділ 3

Що таке Metaspace (або PermGen)?

4. Кешуйте проксі та скрипти 5. TraceClassLoading для налагодження

Мовні версії: English Russian Ukrainian

🟢 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

  1. MaxMetaspaceSize — обов’язковий у Docker. Не ставте занадто близько до реального споживання — це викличе часті Full GC. Запас мінімум 30-50%.
  2. MetaspaceSize = споживання після прогріву
  3. Моніторте витоки ClassLoader
  4. Кешуйте проксі та скрипти
  5. 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]]