Java 内存泄漏-Android.os.Message持有的Android活动
我正在开发一个应用程序,其中90%的活动继承自一个公共活动,所有这些活动都会泄漏,这意味着如果我从Java 内存泄漏-Android.os.Message持有的Android活动,java,android,memory-leaks,Java,Android,Memory Leaks,我正在开发一个应用程序,其中90%的活动继承自一个公共活动,所有这些活动都会泄漏,这意味着如果我从a->B开始,然后B->a(finish()被调用),B的onDestroy()会被调用,但它仍然泄漏(用MAT检查) 泄漏的活动相当大(10MB~),因此在来回运行几次后,应用程序与OOM崩溃 我检查了堆转储,并按照GC根的路径查找泄漏活动,它们都是这样的: 所以我猜是普通超类中的某些东西在泄漏。我已经检查过,当活动被销毁时,所有的BroadcastReceiver和Listener都已注销,并
a->B
开始,然后B->a
(finish()
被调用),B
的onDestroy()
会被调用,但它仍然泄漏(用MAT检查)
泄漏的活动相当大(10MB~),因此在来回运行几次后,应用程序与OOM崩溃
我检查了堆转储,并按照GC根的路径查找泄漏活动,它们都是这样的:
所以我猜是普通超类中的某些东西在泄漏。我已经检查过,当活动被销毁时,所有的BroadcastReceiver和Listener都已注销,并且没有使用处理程序s,也没有可能导致泄漏的匿名内部类(至少在我看来是这样)
泄漏的原因可能是什么?任何帮助都将不胜感激
编辑
我发现有两段代码被注释掉后,活动不再泄漏:
实例化ProgressDialog
的一些代码行
使用匿名Runnable
调用postDelayed
在第一种情况下,对话框的dismise()
函数在销毁之前被调用,所以我不知道为什么会出现问题。在第二种情况下,onPause
中的Runnable
调用removeCallbacks,因此理论上它是正确清理的,不是吗
干杯。问题是postDelayed
中的匿名Runnable
。这个Runnable
是通过基本活动的内容视图的postDelayed()函数调用的,所以它是这样的:
@Override
protected void onResume() {
...
mCallback = new Runnable() { ... };
getContentView().postDelayed(mCallback, mDelay);
}
令人惊讶的是,在onPause()
中删除了此回调:
为什么这没有阻止泄漏对我来说仍然是个谜。起初,我尝试使用getContentView().getHandler().removeCallbacksAndMessages(null)
,它修复了漏洞,但随后该应用程序在看似无关的地方将内容完全分解
最后,修复漏洞的方法是创建一个处理程序
实例,并在此处理程序上调用postDelayed()
和removeCallbacks()
。我的第一个快照将是一个匿名或内部类,它保留对活动上下文的引用。发布你的活动代码,以便我们可以查看。不幸的是,我不能透露代码,它非常庞大和混乱。MAT屏幕截图告诉你什么了吗?它告诉我你正在泄漏上下文,它被一个消息队列持有。首先,验证活动中是否存在任何非静态内部类。非静态内部类中的对象持有对其父类的引用,因此您可能需要对其进行双重检查。还要再次检查您发布的runnable:运行时间是否太长?只要它在消息队列中,活动的上下文就不会被破坏。记录getContentView.postDelayed
和getContentView.removeCallbacks
返回的布尔值会很有趣。在我看来,在视图中公开这些方法是一个非常糟糕的API设计。我会把这两个方法只留在Handler类中。这也让我觉得处理程序的实现可以更加健壮,以防它是另一个。我确实检查了removeCallbacks
的返回值,它总是返回true,对我来说似乎没有什么明显的错误。我同意API的设计有点不可靠,不知道为什么这些函数用于。。。
@Override
protected void onPause() {
...
getContentView().removeCallbacks(mCallback);
mCallback = null;
}