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 组件会造成误报内存泄漏吗?的主要内容,如果未能解决你的问题,请参考以下文章
gcc/linux:CppuTest 使用静态向量显示内存泄漏,误报?
Visual Studio 2008 C++ 误报内存地址位置