了解 Android 应用程序中的内存泄漏

Understanding Memory Leaks in an Android application

我是 Java 编程的新手,有很多 C++ 经验,而且我正在阅读有关引用如何导致 Android 应用程序中的内存泄漏的信息。 This explanation 难倒我了。在 "Lesson #2" 它说:

The point is, the Activity doesn’t know that the lifespan of SomeObject will end when the instance of the Activity ends. If that object remains in memory, it will hold that Activity in memory as well [...].

如我所见(可能是错误的;请纠正我),当 activity 结束时,SomeObject 被销毁(假设不存在对它的其他引用)。 activity 引用 SomeObject,而不是相反。我不明白为什么这里泄露了任何东西,更不用说整个 activity.

这与他们正在为 EventListener 创建匿名 class 这一事实有关。

public void onResume() {
    super.onResume();

    SomeObject object = new SomeObject();

    object.setSuccessListener(new EventListener<Boolean>() {
        public void onEvent(Boolean response) {
            Log.d(TAG_NAME, "Valid response? "+response);
        }
    });

    SomeObjectManager.getSingleton().addObject(object);
}
  • 明确指出这是在 Activity 中完成的 onResume().

  • 匿名 classes(以及非静态内部 classes)隐式引用了它们周围的 class。所以在这种情况下,EventListener 有一个对 Activity 本身的引用。

  • 因此,SomeObject 引用了 Activity,因为它引用了实现 EventListener 的 Anonymous class。

这是您在问题中引用的引文之前的文字:

For instance, in the example above: we’ve attached a reference to our Activity instance to some object, presumably persistent, and in a manager somewhere. The point is...

所以 SomeObjectManager class 在 activity 被销毁时不会消失,它持有对 SomeObject 的引用,而 SomeObject 持有对 EventListener 的引用,而 EventListener 又引用Activity.

所以当你说:

As I see it (probably wrong; please correct me), when the activity ends, SomeObject is destroyed (assuming no other reference to it exists). The activity references SomeObject, not the other way round.

该逻辑中的缺陷是 SomeObject 确实通过 EventListener 引用了 activity。

有帮助吗?

答案如下:How Does this Escape?

如果可以,那么 运行 在调试器中设置断点:

Log.d(TAG_NAME, "Valid response? "+response);

现在检查 'this' 实例有哪些成员。特别是您对 this[=13=].

感兴趣

所以通话很重要:

objectFromBefore.setSuccessListener(null);

看看之前发生了什么:

object.setSuccessListener(new EventListener<Boolean>() {
    public void onEvent(Boolean response) {
        Log.d(TAG_NAME, "Valid response? "+response);
    }
});

SomeObjectManager.getSingleton().addObject(object);

现在链是:

SomeObjectManager -> 单例 -> listofObjects -> 对象

以及对象:

object->successListeners->anonymous EventListener->this$

this$ 这里是你的外部实例,它是 activity.

不幸的是,Activity 很容易泄露。我认识的一些 Android 开发者很高兴(有时是故意)忘记了这个事实。感谢你的关心,知道你想了解更多以避免这种情况。

一些常见的泄漏方法 Activity

1) setting/adding/registering 你的 Activity 作为倾听者或观察者忘记设置 (null)/remove/unregister Activity.

2) 使用静态引用将对 Activity 的引用传递给持有它的任何内容,而不是清除静态引用。 (单身人士就是一个例子)

3) 使用非静态内部 classes。 (匿名内部 class 处理程序就是一个例子)

您可以采取一些措施来避免此类泄漏

1) 记得设置(null)/remove/unregister你的Activity

2) 作为软件设计的一部分,将 Activity 生命周期概念融入到处理 Activity 的组件中。

3) 使内部 class 成为静态的,并且在需要引用外部 class 的地方,使用 Wea​​kReferences

4) 尽可能使用应用程序上下文而不是您的 Activity 上下文。

您的 Activity 将被销毁并重新创建的一些常见情况

1) 如果您允许在您的应用程序中更改方向,Activity 将在从纵向切换到横向时被破坏并重新创建,反之亦然。

2) 使用设备的后退按钮退出您的应用程序将导致当前 Activity 被销毁(即使应用程序本身将保持 运行。)

3) 尽管更为罕见,Android 可以随意终止您的 Activity 以释放资源并保持设备对用户的响应。

您应该熟悉 Android Studio 的设备监视器、hprof-conv 工具和 Eclipse 内存分析器工具。我发现测试我的应用程序以查看它是否泄漏 Activity 的最简单方法是在我进入应用程序时在设备监视器中对其进行内存分析,使用设备后退按钮退出它,然后return 通过单击应用程序托盘中的图标或转到“最近使用”来访问该应用程序。重复此操作几次,然后创建一个内存转储文件。 运行这个转储文件上的hprof-conv工具把它变成MAT可以理解的格式,然后在MAT中打开它。

有很多关于获取内存配置文件和使用 MAT 的教程。只需进行网络搜索。