Как работают soft и phantom ссылки в garbage collector Java?
Что проверяют
Знаете ли вы, как сборщик мусора обращается с объектами разной достижимости и зачем нужна ReferenceQueue. Следом часто спрашивают, почему кэш на SoftReference считается плохой идеей и чем заменили finalize().
Как отвечать
Начните с порядка достижимости: сильная, мягкая, слабая, фантомная. Все обёртки лежат в java.lang.ref:
SoftReference: объект собирается, только когда памяти не хватает. JVM гарантирует, что все мягкие ссылки очистят доOutOfMemoryError, а в остальном решает сама. В HotSpot срок жизни зависит от свободного места в куче и флага-XX:SoftRefLRUPolicyMSPerMB;WeakReference: очищается на первой же сборке, которая заметит, что сильных ссылок нет. На ней построенWeakHashMap;PhantomReference:get()всегда возвращаетnull, достать объект через неё нельзя. Её смысл в уведомлении: когда объект стал фантомно достижимым, ссылка попадает вReferenceQueue, и вы освобождаете связанный внешний ресурс.
Главное практическое применение фантомных ссылок это java.lang.ref.Cleaner из Java 9. Вы регистрируете объект и действие очистки, а Cleaner сам держит фантомную ссылку и поток, который разбирает очередь. Это замена finalize(), который объявлен устаревшим к удалению (JEP 421). Действие очистки не должно ссылаться на сам объект, иначе он никогда не станет недостижимым.
Про кэш скажите прямо: мягкие ссылки дают кэш без контроля размера, который чистится при давлении на память и удлиняет паузы GC. Обычно берут кэш с лимитом, например Caffeine с maximumSize.
Где спотыкаются
Говорят, что фантомная ссылка указывает на уже удалённый объект. Она ставится в очередь, когда объект стал недостижим, а память освобождается после очистки ссылки. До Java 9 фантомные ссылки не очищались автоматически, и объект держался в памяти, пока код не вызовет clear().
Показывают пример с System.gc() и сразу queue.poll(). System.gc() лишь просьба, poll() не ждёт, так что результат случаен. Нужен queue.remove(timeout).
Забывают, что сам объект Reference должен оставаться сильно достижимым. Если потерять ссылку на PhantomReference, её соберут, и уведомление не придёт.