Navigation Arch 组件会造成误报内存泄漏吗?

Posted

技术标签:

【中文标题】Navigation Arch 组件会造成误报内存泄漏吗?【英文标题】:Could Navigation Arch Component create a false positive memory leak? 【发布时间】:2020-04-17 14:20:22 【问题描述】:

我对内存泄漏以及可能导致它们的原因有基本的了解。这就是为什么我不明白我的代码是否有问题或者是误报。由于项目不小,我不知道我应该分享代码的哪一部分。但是请在 cmets 中告诉我,我会添加所需的代码。

我使用导航架构组件并遵循 MVVM 模式。我在项目开发后期添加了 LeakCanary 库,当我在屏幕之间导航时,它立即开始向我发出有关保留实例的警告。

当我将片段添加到后台堆栈时会出现问题。随着每个将片段添加到后台堆栈,保留实例的计数器都会增加。当达到阈值 5 时,LeakCanary 转储堆并提供报告。

但是如果我点击后退按钮并返回到前一个屏幕,则保留实例的计数器会减少,最终,当返回到第一个屏幕时,所有保留实例都会消失。

如果我查看堆分析报告,它说变量 coordinatorLayout 是对 xml 中 CoordinatorLayout 的引用已泄漏。如果我删除变量及其所有用法并再次运行应用程序,我会看到同样的问题,但现在有另一个变量是对 xml 中另一个视图的引用。我试图删除 LeakCanary 报告为泄漏的所有视图及其使用情况。当它说 TextView 泄漏时,它只是用于在 onViewCreated 中设置文本而没有在其他任何地方使用,我开始怀疑我的代码中存在问题。

我分析了片段中的生命周期方法调用,并注意到当我导航到前一个片段的新屏幕时,所有方法直到并包括 onDestroyView 都被调用,而不是 onDestroy。当我单击返回时,onDestroy 被调用以获取位于返回堆栈顶部的片段并且保留实例计数器减少。

我怀疑 Navigation 组件在返回堆栈时保留片段的实例,而 LeakCanary 将其视为泄漏。

【问题讨论】:

【参考方案1】:

这就是后台堆栈上的 Fragment 的工作方式(并且 Navigation 只使用现有的 Fragment API):Fragment 的视图被破坏,但 Fragment 本身并未被破坏 - 它们保持在CREATED 状态,直到你击中后面按钮并返回到 Fragment(之后将再次调用 onCreateView(),然后您将返回到 RESUMED)。

根据Fragments: Past, Present, and Future talk,Fragments 的未来变化之一是选择在后台销毁 Fragment 的选项,而不是拥有两个独立的生命周期。目前尚不可用。

您必须取消对 onDestroyView 中视图的引用,因为这表明 Fragment 系统不再使用该视图,如果您不继续参考,它可以安全地被垃圾收集视图。

【讨论】:

android View Binding 能解决这个问题吗?我找不到任何关于 View Binding 视图的引用(可能是绑定对象本身)是否在 onDestroyView 中使用 View Binding 自动“取消”的文档。 @TimMalseed - 您需要自己取消对绑定对象的引用,不会自动发生任何事情。 @Pauland - 一直都是这样,是的。在我在答案中链接的谈话中引用的更改完成之前,情况将继续如此。 如果使用DataBinding,如果我们将绑定的所有者设置为viewLifecycleOwner,是否可以解决这个问题?绑定应该会自动清除吧? @Emmanuel - 您需要删除对绑定对象本身的引用,因为它包含对其拥有的视图的硬引用。

以上是关于Navigation Arch 组件会造成误报内存泄漏吗?的主要内容,如果未能解决你的问题,请参考以下文章

MFC误报内存泄露的修复

MFC误报内存泄露的修复

gcc/linux:CppuTest 使用静态向量显示内存泄漏,误报?

Visual Studio 2008 C++ 误报内存地址位置

如何修复或抑制误报“您可能在组件渲染函数中有无限更新循环”Vue 警告

关于自动寻路(Navigation)的初级总结