Как управлять разными видами ссылок в Java
Что проверяют
Понимаете ли вы, как сборщик мусора обращается с объектами, до которых можно добраться только через java.lang.ref, и где это применяется на практике. Перечислить четыре вида мало, важны сценарии и ловушки. Следом часто спрашивают про WeakHashMap, утечки через ThreadLocal или замену finalize().
Как отвечать
- сильная ссылка: обычная переменная или поле. Пока объект достижим по цепочке сильных ссылок от корней GC, он не будет собран;
SoftReference: объект собирается, когда памяти мало. Гарантируется, что все мягко достижимые объекты будут очищены доOutOfMemoryError. В HotSpot время их жизни регулирует флаг-XX:SoftRefLRUPolicyMSPerMB;WeakReference: не мешает сборке, объект пропадает при первой сборке, которая до него доберётся. На этом построеныWeakHashMapсо слабыми ключами и внутренняя таблицаThreadLocal;PhantomReference:get()всегда возвращаетnull. Нужна, чтобы узнать, что объект уже недостижим, и освободить внешний ресурс. Имеет смысл только вместе сReferenceQueue.
ReferenceQueue получает ссылку после того, как объект стал недостижим нужным образом, и позволяет подчистить связанные с ним данные. Для освобождения ресурсов с Java 9 есть java.lang.ref.Cleaner: он построен на фантомных ссылках и заменяет finalize(), который объявлен устаревшим и помечен к удалению.
Про кэши скажите отдельно: сейчас их строят на Caffeine с ограничением по размеру и времени жизни. У него есть weakKeys() и softValues(), но это исключение. Кэш на мягких ссылках под нагрузкой ведёт себя непредсказуемо: давит на GC и теряет содержимое целиком.
Где спотыкаются
Дважды вызывают get(): проверили на null, а при втором вызове объекта уже нет. Результат сохраняют один раз в локальную переменную, она и держит объект.
Кладут в WeakHashMap значение, которое ссылается на свой ключ. Значения хранятся сильно, ключ никогда не станет слабо достижимым, и получается утечка. С ThreadLocal в пуле потоков похожая история: без remove() значение живёт вместе с потоком.
Считают WeakReference хорошим кэшем. Молодой объект исчезнет при первой же минорной сборке, и попаданий почти не будет.