Как определяется, что объект больше не используется и может быть удален сборщиком мусора в Java
Что проверяют
Знаете ли вы про достижимость от корней и понимаете ли, почему счётчика ссылок недостаточно.
Как отвечать
Объект считается мусором, если он недостижим от корней сборки. Сборщик обходит граф ссылок, начиная с корней, помечает всё, до чего дошёл, а непомеченное считает мусором.
Корнями являются:
- локальные переменные и параметры в кадрах стеков всех живых потоков;
- статические поля классов, загруженных живыми загрузчиками;
- ссылки из нативного кода;
- сами активные потоки и объекты, используемые как мониторы.
Важно, почему выбран именно этот подход, а не подсчёт ссылок: счётчик не видит циклов. Два объекта, ссылающиеся друг на друга и больше ни на кого не нужные, имели бы ненулевые счётчики и никогда не освободились бы. Обход от корней эту проблему решает по построению: изолированный цикл просто недостижим.
Что стоит добавить:
- виды ссылок влияют на решение: сильная удерживает объект всегда, мягкая до нехватки памяти, слабая не удерживает вовсе, фантомная нужна для действий после уничтожения;
- поколения: большинство объектов умирает молодыми, поэтому молодое поколение собирается часто и быстро, а пережившие переезжают в старое;
- недостижимость не означает немедленное освобождение. Момент сборки решает сборщик, и
System.gc()это лишь пожелание. Полагаться на время освобождения нельзя; finalizeустарел и удалён: момент вызова не гарантирован, объект задерживается на лишний цикл, исключения теряются. Для освобождения ресурсов естьtry-with-resourcesиCleaner.
Практическое следствие: утечка в Java это не невозможность освободить, а случайно оставшаяся ссылка. Классика это статическая коллекция, куда складывают и не удаляют, и слушатель, которого не отписали.
Где спотыкаются
Называют подсчёт ссылок механизмом сборки в Java.
Считают, что System.gc() гарантированно запускает сборку.
Не могут объяснить, что такое корни сборки.
Уверены, что утечек в Java не бывает.