Navigation Arch Component会造成假阳性内存泄漏吗?


14

我对内存泄漏以及可能导致它们的原因有基本的了解。这就是为什么我不明白我的代码中是否有问题还是误报的原因。我不知道我应该共享代码的哪一部分,因为该项目并不小。但是,请在评论中让我知道,然后我将添加所需的代码。

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

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

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

如果我查看堆分析报告,它表示变量coordinatorLayout是CoordinatorLayoutxml中的引用。如果删除该变量及其所有用法,然后再次运行该应用程序,我会看到相同的问题,但是现在有了另一个变量,该变量引用了xml中的另一个视图。我试图删除LeakCanary报告为泄漏的所有视图及其用法。当它说a TextView只是用于设置文本onViewCreated而不在其他地方使用时,正在泄漏,我开始怀疑我的代码是否有问题。

我分析了片段中的生命周期方法调用,并注意到当我导航到先前片段的新屏幕时,直到(包括)所有方法onDestroyView都被调用,但没有被调用onDestroy。当我单击返回时,onDestroy将调用位于后堆栈顶部和保留实例顶部的片段,计数器会减少。

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

Answers:


24

这就是后堆栈上的片段的工作方式(导航仅使用现有的Fragment API):片段的视图被破坏了,但片段本身并未被破坏-它们保持CREATED状态,直到您按下后退按钮并返回到片段为止(此后onCreateView()将再次被调用,您将回到RESUMED)。

根据Fragments:过去,现在和将来的演讲,Fragments的未来变化之一是选择销毁后端堆栈上的Fragment的选项,而不是具有两个单独的生命周期。目前尚不可用。

您必须取消对视图的引用,onDestroyView因为这是Fragment系统不再使用该视图的标志,并且如果不继续引用该视图,则可以安全地对其进行垃圾回收。


2
Android视图绑定是否可以解决此问题?我找不到任何有关View Binding视图(也许是绑定对象本身)的引用是否随View Binding自动被“淘汰”的文档onDestroyView
蒂姆·马尔塞德

3
@TimMalseed-您需要自己使对绑定对象的引用无效,没有自动进行的操作。
ianhanniballake

1
@Emmanuel-您需要删除对绑定对象本身的引用,因为它拥有对其所拥有的视图的硬引用。
ianhanniballake

1
@Emmanuel-您随时可以提出功能请求
ianhanniballake

1
@Emmanuel-我认为这肯定是行为上的改变(这可能意味着它是一个单独的选择加入标志),但是拥有正确的LifecycleOwner将足以为它解决整个内存问题。
ianhanniballake
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.