Для чего нужны soft ссылки в Kotlin
Что проверяют
Знаете ли вы, что своих soft-ссылок в Kotlin нет и на Android это java.lang.ref.SoftReference из Java. Главный уточняющий вопрос: стали бы вы строить на них кеш картинок и почему документация Android отвечает «нет».
Как отвечать
Начните с иерархии ссылок в JVM:
- сильная: обычная ссылка, пока она есть, объект не соберут;
SoftReference: объект соберут, если памяти не хватает. Гарантия одна: все soft-ссылки будут очищены до того, как рантайм броситOutOfMemoryError;WeakReference: объект соберут при первой же сборке, на которой на него не осталось сильных ссылок. Подходит, чтобы не удерживатьActivityилиViewиз долгоживущего объекта;PhantomReference:get()всегда возвращаетnull, служит для действий после сборки объекта черезReferenceQueue. На современной JVM для этого естьCleaner.
Идея soft-ссылок в кеше: держим тяжёлый объект, пока память есть, и отдаём его сборщику при нехватке. На Android это не работает: в документации SoftReference прямо сказано, что для кеширования они неэффективны. Рантайм не знает, какие объекты дорого пересоздавать, и не умеет выбирать между очисткой ссылки и ростом кучи.
Правильный ответ для Android: кеш с явным лимитом, LruCache из android.util или androidx.collection, с размером от доступной памяти и переопределённым sizeOf. На нехватку памяти реагируют через onTrimMemory. Для картинок берут Coil или Glide: у них основной кеш на сильных ссылках с LRU, а weak-ссылки служат лишь дополнительным слоем.
Где спотыкаются
Говорят, что soft-ссылки предотвращают утечки. От утечки Activity спасает weak-ссылка или, лучше, правильная привязка к жизненному циклу, а soft-ссылка удержит объект ещё дольше.
Проверяют ref.get() != null, а потом снова вызывают get(). Между вызовами объект может исчезнуть, поэтому значение сначала сохраняют в локальную переменную.
Хранят SoftReference в обычной Map и не удаляют записи. Объекты соберут, а ключи с пустыми ссылками останутся и будут копиться.