Как избежать утечек памяти в Android
Что проверяют
Знаете ли вы типовые источники утечек и понимаете ли общий принцип, а не список рецептов.
Как отвечать
Общий принцип один: утечка это когда объект с коротким временем жизни удерживается объектом с длинным. Почти всегда короткий это активити, фрагмент или его представление, а длинный это синглтон, статическое поле или фоновая задача.
Типовые источники и лечение:
- контекст активити в долгоживущем объекте. Репозиторий, менеджер, кэш должны получать
applicationContext. Статическое поле с активити удержит экран навсегда; - анонимные классы и внутренние классы, неявно держащие внешний объект. Обработчик с отложенным сообщением или слушатель, зарегистрированный и не снятый, тянет за собой весь экран. Лечение: снимать подписку в парном методе жизненного цикла;
- ссылка на разметку во фрагменте. Представление уничтожается в
onDestroyView, а сам фрагмент живёт дальше в стеке возврата. Ссылку обнуляют там же, иначе удерживается всё дерево представлений; - неправильный владелец жизненного цикла. Подписка на данные во фрагменте привязывается к
viewLifecycleOwner, а не к самому фрагменту, иначе после возврата подписок станет две; - корутины вне области. Работа запускается в
viewModelScopeилиlifecycleScope, тогда она отменится сама. Запуск в глобальной области переживает экран; - незакрытые ресурсы: курсоры, потоки, приёмники широковещательных сообщений, датчики.
Про слабые ссылки: они не решение, а маскировка. Если объект удерживается неправильно, лучше исправить владение, а не прятать проблему.
Инструменты: LeakCanary находит утечки автоматически прямо на устройстве и показывает цепочку удержания, профилировщик памяти в среде разработки позволяет снять дамп кучи и посмотреть, кто держит объект. Проверять надо в первую очередь сценарий поворота экрана и многократного входа и выхода с экрана.
Где спотыкаются
Держат контекст активити в синглтоне.
Подписываются с владельцем-фрагментом вместо владельца-представления.
Не обнуляют ссылку на разметку.
Оборачивают всё в слабые ссылки вместо исправления владения.