Получить доступ

GC: корни, достижимость и типы ссылок

GC roots и reachability, strong/soft/weak/phantom-ссылки, Cleaner вместо finalize и утечки через сильные ссылки.

GC roots и достижимость

Сборщик считает объект живым, если до него есть путь по ссылкам от какого-то GC root. Корни — это локальные переменные и операнды в стеках живых потоков, статические поля загруженных классов, JNI-ссылки, активные мониторы и т.п.

Всё, до чего нельзя дойти от корней, — мусор. Поэтому «утечка памяти» в Java — это не недостижимый объект (он соберётся), а наоборот: объект, который всё ещё достижим от корня, хотя уже не нужен.

Граф достижимости от корней GC к живым объектам и остров недостижимых объектов; рядом лесенка силы ссылок: сильная, мягкая, слабая, фантомная.
Объект жив, пока достижим от корней GC. Сила ссылки убывает: сильная → мягкая → слабая → фантомная.

Четыре типа ссылок

Strong — обычная ссылка: пока она есть, объект не собирается. Soft (SoftReference) — объект доживёт до нехватки памяти, потом будет собран; подходит для кэшей, которые не жалко сбросить под давлением. Weak (WeakReference) — объект собирается при первой же сборке, если на него нет сильных ссылок; основа WeakHashMap и канонизирующих кэшей. Phantom (PhantomReference) — не даёт доступа к объекту, лишь сигнализирует, что он уже финализирован и память вот-вот освободится.

Слабые и фантомные ссылки регистрируют в ReferenceQueue, чтобы узнавать момент их очистки и выполнять пострешур.

Map<Key, Heavy> cache = new WeakHashMap<>();
// запись исчезнет автоматически, когда на Key не останется сильных ссылок

Cleaner вместо finalize

finalize() устарел и опасен: момент вызова не гарантирован, он тормозит сборку, может «воскресить» объект и проглатывает исключения. В современном коде его не используют.

Для освобождения нативных ресурсов применяют java.lang.ref.Cleaner (на основе PhantomReference + ReferenceQueue), но как страховку. Основной способ детерминированно освобождать ресурсы — AutoCloseable + try-with-resources, а не финализация.

Утечки через сильные ссылки

Типичные источники утечек: объекты, забытые в долгоживущей коллекции или статике; не отписанные слушатели (listener держит подписчика); ThreadLocal, не очищенный в пуле потоков (поток живёт долго и держит значение); ключи в обычной HashMap, которые «должны были» исчезнуть.

Диагностика — heap dump и анализ доминаторов/путей до GC root: инструмент показывает, какая сильная цепочка не даёт объекту умереть.

Как отвечать на собеседовании

Объясните reachability от GC roots и переопределите «утечку» как достижимый-но-ненужный объект. Разложите strong/soft/weak/phantom с практикой (Soft — кэш, Weak — WeakHashMap, Phantom/Cleaner — пострешур ресурсов), скажите, что finalize устарел в пользу try-with-resources/Cleaner, и назовите классические источники утечек (ThreadLocal в пуле, не отписанные listeners).

Вопросы по теме

Читайте также

Закрытая бета

Знать тему — половина дела

На живом собеседовании sotto слышит вопрос интервьюера и показывает короткий ответ и план. Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем