移除碎片后内存未释放

13

我有一个带有RecyclerViewFragment

在这个RecyclerView中,我可能偶尔会下载并显示图像(使用Glide加载到ImageView中)。

因此,当我打开Fragment时,使用的内存有时会从大约30MB跳至大约100MB甚至更多。

在持有FragmentActivity完成后,内存不会释放。它保持与之前相同的状态。

我查看了Glide文档,显然我们不必担心在RecyclerView中释放Bitmaps。这是一个巨大的问题,因为应用程序经常因此而崩溃。

当移除Fragment时,应该如何正确处理释放内存?

编辑:另一项观察结果

我注意到的另一件事是,如果我完成Activity,然后再次启动相同的Activity。内存将短暂地跳回原点,然后再次上升到100MB,这让我相信内存在重新启动Fragment之前被清除了。

2个回答

10

在Android中,垃圾收集有时会成为一个痛点。许多开发人员忽视了这个问题,只是不停地开发,没有任何资源分配的意识。

这当然会导致内存问题,例如泄漏、OOM和不必要的资源绑定。没有任何自动方式可以释放内存。在任何情况下,您都不能仅仅依赖于垃圾收集器来释放内存。

每当通过Fragment或Activity的onDestroy()方法时,您应该擦除应用程序中不再需要的任何构造。您可以执行以下操作:

  1. 避免使用匿名监听器实例。创建监听器并在不再需要它们时销毁它们。
  2. 将所有监听器(无论是单击、长按等)设置为null
  3. 清除所有变量、数组。对Activity/Fragment内包含的所有类和子类应用相同的过程
  4. 在对给定类执行任何上述步骤时,将变量设置为null(适用于所有变量)

我最终所做的就是创建一个接口,如下所示:

public interface clearMemory(){
    void clearMemory();
}

并将其应用于每个类中,无论是Activity、Fragment还是普通类(包括适配器、自定义视图等)。

然后,当类被销毁时(因为应用程序被销毁或者我感觉有必要这样做),我会调用该方法。注意不要在正常运行时处置。

@Override
public void onDestroy(){
    clearMemory();
}

public void clearMemory(){
    normalButtonOnClickListener = null;
    normalButton.setOnClickListener(null);
    normalButton = null;
    myCustomClass.clearMemory(); // apply the interface to the class and clear it inside
    myCustomClass = null;
    simpleVariable = null;
    ...        
}

通过系统化实现这一点,我的应用程序的内存管理变得更加简单而高效。这样就可以确切地了解/控制内存何时以及如何被释放。


谢谢,这确实有帮助。我明天会尝试一下(虽然在整个应用程序中执行可能需要一些时间),然后告诉你结果。 - Guy
当您说要清除所有变量时,这意味着实例变量,对吗?如果我在onCreate方法中创建一个变量,那么在停止使用它后,我也应该清除它吗? - Guy
是的。一旦您知道不再需要分配的所有内容都必须/应该立即处理。 作为比喻: 1)您购买了一张一次性纸张。您在纸上写下了一些关于您一天的事实。 2)您将在整个一天中使用这张纸,但您知道您永远不需要这张纸。 3)到了一天结束时,您意识到这张纸已经完成了它的使命。 4)您通过撕碎并将其扔进垃圾桶来丢弃纸张。 现在,将“纸张”理解为您使用的任何变量,“一天”为您的活动生命周期。 - Ricardo Vieira
看起来我有很多代码重构要做 :) 谢谢!另外一个问题,您认为在Fragment中处理变量的最佳位置是什么?我了解到onDestroy和onDestroyView可能并不总是被调用。所以现在,我正在onStop上处理它。那样可以吗? - Guy
非常好的评论。请看一下这个 StackOverflow 的帖子:https://dev59.com/0njZa4cB1Zd3GeqPd21r 问候! - Ricardo Vieira

4
这是对Ricardo回答的补充。
您可以添加以下代码来启动Android中的垃圾回收:
Runtime.getRuntime().gc(); 注意:在将所有本地变量设置为null后调用此函数。执行此代码并不能保证系统会在您的应用程序上进行垃圾回收,它只是提示现在可能是一个好时机。
我在所有我的活动的onDestroy()中使用了这个方法,当我想要时它总是有效的。
试一试,它可能会对您有所帮助。

没错。我们基本上可以调用System.gc()来“提示”系统,它最终会执行收集所有没有引用的对象。受控内存管理始终是任何应用程序的重要组成部分! - Ricardo Vieira
1
这个答案对我非常有帮助。我一直在尝试清除销毁资源,但只有在启动垃圾回收后才会减少内存。谢谢。 - Aung Si Min Htet
如果我在每次调用popBackStack后都调用垃圾回收器会发生什么? - uzaysan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接