导航 Arch 组件是否会造成误报内存泄漏?

Mar*_*rat 34 android memory-leaks kotlin leakcanary android-architecture-navigation

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

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

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

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

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

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

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

ian*_*ake 60

这就是返回堆栈上的 Fragment 的工作方式(并且导航只使用现有的 Fragment API):Fragment 的视图被销毁,但 Fragment 本身没有被销毁 - 它们保持在CREATED状态,直到您点击后退按钮并返回到 Fragment (之后onCreateView()将再次调用,您将返回到RESUMED)。

根据Fragments: Past, Present, and Future 谈话,Fragments 的未来变化之一是选择销毁后端堆栈中的 Fragment,而不是具有两个单独的生命周期。目前还没有这个功能。

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

  • Android View Binding 能解决这个问题吗?我找不到任何关于对视图绑定视图的引用(可能是绑定对象本身)是否在带有视图绑定的“onDestroyView”中自动“清空”的文档。 (7认同)
  • @TimMalseed - 您需要自己清空对绑定对象的引用,没有任何自动发生的事情。 (5认同)
  • @Pauland - 情况一直如此,是的。在我在答案中链接的演讲中引用的更改发生之前,情况将继续如此。 (2认同)
  • @Emmanuel - 您需要删除对绑定对象本身的引用,因为它持有对其拥有的视图的硬引用。 (2认同)