Может ли компонент Navigation Arch создать ложную положительную утечку памяти?

14

У меня есть базовые знания об утечках памяти и о том, что может их вызвать. Вот почему я не понимаю, если у меня есть проблема в моем коде или это ложный положительный результат. Я не знаю, какой частью кода я должен поделиться, так как проект не маленький. Но просто дайте мне знать в комментариях, и я добавлю необходимый код.

Я использую компонент навигационной арки и следую шаблону MVVM. Позже я добавил библиотеку LeakCanary при разработке проекта, и она сразу же начала давать мне предупреждения о сохраненных экземплярах при переходе между экранами.

Проблема возникает, когда я добавляю фрагменты в задний стек. С каждым добавленным фрагментом в задний стек счетчик сохраненных экземпляров увеличивается. Когда он достигает порогового значения 5, LeakCanary сбрасывает кучу и выдает отчет.

Но если я нажму кнопку «Назад» и вернусь к предыдущим экранам, то счетчик сохраненных экземпляров уменьшится, и в конечном итоге, когда вернется на 1-й экран, все сохраненные экземпляры исчезнут.

Если я посмотрю на отчеты по анализу кучи, то там будет сказано, что переменная координаторLayout, которая является ссылкой на CoordinatorLayoutXML, просочилась. Если я удаляю переменную и все ее использование и снова запускаю приложение, я вижу ту же проблему, но теперь с другой переменной, которая является ссылкой на другое представление в xml. Я попытался удалить все виды и их использование, которые LeakCanary сообщил как утечка. Когда он сказал, что a TextView, который просто используется для установки текста onViewCreatedи не используется где-либо еще, протекает, я начал сомневаться, что в моем коде есть проблема.

Я проанализировал вызовы методов жизненного цикла во фрагментах и ​​заметил, что при переходе к новому экрану для предыдущего фрагмента все методы до и включая onDestroyViewвызываются, но неonDestroy . Когда я нажимаю назад, onDestroyвызывается фрагмент, который был на вершине заднего стека, и счетчик сохраненных экземпляров уменьшается.

Я подозреваю, что компонент Navigation хранит экземпляр фрагмента, когда он находится в заднем стеке, а LeakCanary видит в нем утечку.

Марат
источник

Ответы:

24

Вот как работают фрагменты в заднем стеке (а Navigation просто использует существующие API-интерфейсы фрагментов): представление фрагмента уничтожается, но сам фрагмент не уничтожается - они остаются в CREATEDсостоянии до тех пор, пока вы не нажмете кнопку возврата и не вернетесь к фрагменту. (после чего onCreateView()будет вызван снова, и вы вернетесь к RESUMED).

Согласно разговорам « Фрагменты: прошлое, настоящее и будущее» , одно из будущих изменений, которые появятся в «Фрагментах», - это опция уничтожения фрагментов в заднем стеке вместо двух отдельных жизненных циклов. Это еще не доступно на данный момент.

Вы должны обнулить свои ссылки на представления, так onDestroyViewкак это признак того, что представление больше не используется системой Fragment, и его можно безопасно собирать, если это не было вашей постоянной ссылкой на представление.

ianhanniballake
источник
2
Решает ли Android View Binding эту проблему? Я не могу найти никакой документации о том, автоматически ли обнуляется ссылка на представления View Binding (возможно, сам объект привязки) onDestroyViewс помощью View Binding.
Тим Малсеид
3
@TimMalseed - вам нужно самостоятельно обнулить ссылку на объект привязки, автоматически ничего не происходит.
ianhanniballake
1
@Emmanuel - вам нужно отбросить ссылку на сам объект привязки, поскольку он содержит жесткую ссылку на принадлежащие ему представления.
января
1
@ Emmanuel - вы всегда можете отправить запрос на добавление !
Ианханнибаллейк
1
@Emmanuel - я думаю, что это, безусловно, будет изменение поведения (что может означать, что это отдельный флаг выбора), но наличие правильного LifecycleOwner будет достаточно информации, чтобы исправить целый ряд проблем с памятью.
Ианханнибаллейк