24просмотров
29 декабря 2025 г.
Score: 26
👻 Memory Leak в PermGen/Metaspace. Когда классы не хотят умирать. Часть 2. ❓ Почему это специфично для кастомных ClassLoader'ов? Системный ClassLoader (например, AppClassLoader) живёт всегда, поэтому его классы никогда не выгружаются. Проблема возникает только когда: 1. Вы создаёте временные ClassLoader'ы (для плагинов, hot deploy)
2. Хотите их выгрузить (например, при обновлении плагина)
3. Но они не выгружаются из-за таких циклических ссылок ✔️ Как исправить? 1. Избегайте статических полей в динамически загружаемых классах
2. Используйте WeakReference для кэшей:
private static final WeakReference<Cache> CACHE_REF = new WeakReference<>(new Cache());
3. Явно очищайте статики при выгрузке:
public static void cleanup() { CACHE = null; CONTEXT.remove(); // etc
}
4. Правильная иерархия загрузчиков (родительские загрузчики для общих библиотек) 📈 Диагностика # Смотрим загрузчики классов
jcmd <pid> GC.class_histogram | grep -i classloader # Или в JVisualVM/Mission Control
# Metaspace постоянно растёт при redeploy 📌 Итог: Утечка возникает из-за циклической зависимости через метаданные класса. ClassLoader ссылается на класс, класс имеет статическое поле (которое держит класс "живым"), а класс в своих метаданных ссылается на ClassLoader. Сборщик мусора не может разорвать этот цикл, потому что ссылка из класса на ClassLoader — не обычная ссылка в куче, а служебная ссылка в метаданных. Это одна из самых коварных утечек, потому что её не видно в обычных heap dump'ах — нужно смотреть именно на Metaspace и цепочки ClassLoader'ов. ✈️Подписаться: @iamjavadev #memoryleak #classloader #metaspace #сакральныезнания