Вопрос 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]]