Что такое 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]]