Как понять, что переменную можно удалить из памяти
Что проверяют
Понимаете ли вы, что в Kotlin и Java на Android память вручную не освобождают, и знаете ли, по какому правилу это делает сборщик мусора ART. Следом почти всегда просят назвать типичные утечки и рассказать, как их искать.
Как отвечать
Уточните формулировку: удалить переменную нельзя, освобождается объект, на который она ссылалась. Сборщик считает объект мусором, когда до него нельзя дойти по ссылкам от корней: локальных переменных живых потоков, статических полей, JNI-ссылок. Счётчик ссылок тут ни при чём: два объекта, ссылающиеся друг на друга, тоже соберутся, если до них не добраться от корней.
Практические выводы:
- локальная переменная перестаёт держать объект, когда метод завершился. Объект становится доступен для сборки, но когда его соберут, решает сборщик;
- поле долгоживущего объекта держит свой объект, пока жив владелец. Присваивание
nullимеет смысл именно здесь, например_binding = nullвonDestroyView, потому что фрагмент переживает свою View; - статическое поле или синглтон живёт столько же, сколько процесс. Ссылка из него на
Activityозначает утечку всего экрана, поэтому в долгоживущие объекты передаютapplicationContext.
Типичные утечки: неотписанные слушатели, внутренние и анонимные классы с неявной ссылкой на Activity, отложенные сообщения Handler, корутины в GlobalScope вместо viewModelScope или lifecycleScope, Context экрана внутри ViewModel.
Искать их удобно через LeakCanary: он следит за уничтоженными Activity, фрагментами и ViewModel, снимает дамп кучи и показывает цепочку ссылок до корня. Вручную то же делается в Memory Profiler Android Studio.
Где спотыкаются
Говорят, что утечка это объект, который живёт без ссылок. Наоборот: утечка возникает, когда ненужный объект кто-то всё ещё держит.
Предлагают вызывать System.gc(). Это лишь подсказка системе, утечку она не лечит.
Лепят WeakReference везде. Проблема обычно в жизненном цикле: слушателя нужно отписать в парном колбэке, а не прятать за слабой ссылкой.