Ответ
В Kotlin есть два типа ссылок:
- Strong references – обычные ссылки, удерживающие объект в памяти
- Weak/Soft references – из пакета
java.lang.ref, позволяют GC собирать объекты
Пример с WeakReference:
val obj = Any()
val weakRef = WeakReference(obj)
// После GC weakRef.get() может вернуть null
Особенности:
- WeakReference полезны для кешей, чтобы избежать утечек памяти
- SoftReference реже очищаются GC чем Weak
- Для работы с ссылками в Android часто используют
WeakHashMap
Пример с WeakProperty:
var heavyObject by Weak() // делегат из kotlin.properties Ответ 18+ 🔞
А, ну вот, классика жанра! Сидишь ты такой, пишешь на Kotlin, думаешь — о, какой я умный, память оптимизирую. А потом бац — утечка памяти, и приложение твоё накрывается медным тазом. Так что давай разберёмся, что к чему, пока не будет вам хиросима и нигерсраки в рантайме.
Вот смотри. Всё начинается с обычных ссылок, они же Strong references. Это как твой назойливый друг, который вцепился в тебя мёртвой хваткой и не отпускает, пока ты ему не скажешь «иди на хуй» явно. Пока есть такая ссылка на объект — сборщик мусора (GC) его не тронет, хоть ты тресни. Объект живёт, память жрёт, всё по-взрослому.
Но иногда это пиздец как неудобно. Представь кеш картинок. Загрузил ты их, ссылки держишь, а пользователь уже ушёл с экрана. Картинки не нужны, но память-то они едят! Вот тут на сцену выходят Weak и Soft references из java.lang.ref. Это уже не друзья, а так, знакомые. Они объект не удерживают.
Смотри, как это выглядит:
val obj = Any() // Вот наш объект, на него есть сильная ссылка
val weakRef = WeakReference(obj) // А вот слабая ссылка на него же
// Допустим, мы тут удаляем сильную ссылку: obj = null
// Потом происходит сборка мусора...
// И после этого weakRef.get() может спокойно вернуть null. Объект собрали!
В чём прикол? WeakReference — это как обещание «я позвоню». Как только на объект не осталось сильных ссылок, GC его прибьёт при первом же удобном случае, и твоя слабая ссылка опустеет. Полезно для кешей, где «есть — хорошо, нет — не страшно». SoftReference — чуть покрепче. GC будет собирать их в последнюю очередь, обычно когда память уже реально на исходе. Типа «запасной аэродром».
В андроиде, чтобы не изобретать велосипед, часто юзают WeakHashMap. Это такая мапа, где ключи хранятся по слабым ссылкам. Удалился ключ из памяти — запись из мапы автоматом выпиливается. Красота!
А ещё в Kotlin есть прикольный синтаксический сахар — делегаты. Можно не заморачиваться с созданием WeakReference руками, а сделать так:
var heavyObject by Weak() // делегат из kotlin.properties
Выглядит чисто, да? Объявил переменную, а за кулисами она привязана к слабой ссылке. Удобно, ёпта. Главное — помнить, что heavyObject в любой момент может превратиться в null, так что проверяй наличие, а то получишь NullPointerException и волнение ебать на ровном месте.
Короче, юзай слабые ссылки с умом, где нужно избегать утечек, но не жди от них стабильности. Это не железобетонная гарантия, а так, намёк сборщику мусора.