我正在使用MemoryAnalyzer工具查找Android应用程序中的内存泄漏。所以我运行我的应用程序,访问所有活动,然后按回去,直到我到达桌面。然后我使用DDMS来获取内存转储(已经多次按原因GC )。
然后我使用OQL查询select * from instanceof android.app.Activity
查找泄漏活动,然后按合并到GC根目录的最短路径 - >排除泄漏对象上的所有幻像/弱/软/等参考。在这里我有这张照片:
所以系统中的某个地方似乎有一个静态对象BubblePopupHelper.sHelper
,它保留了对我活动中EditText
视图的引用,导致整个活动泄露!但这是什么BubblePopupHelper
?我在official docs中找不到关于此课程的任何信息。如何防止我的活动被这个奇怪的对象引用而留在内存中?
我在LG L40设备上测试,运行API19
答案 0 :(得分:9)
我的泄漏检测工具定期报告相同的泄漏,仅来自LG手机:
object com.squareup.SomeActivity
`-mContext of object android.widget.EditText
`-mView of object android.widget.BubblePopupHelper
`-sHelper of class android.widget.BubblePopupHelper
制造商喜欢在幕后更改Android SDK的私有API。这是LG引入的内存泄漏。
从我可以收集的内容来看,专注的EditText使用了BubblePopupHelper,可能会显示一些复制/粘贴弹出窗口或文本句柄。由于一次只有一个聚焦编辑文本,因此他们使帮助者成为一个单例,并且它保留了对最新编辑文本的引用。
这意味着整个活动&它的整个视图层次结构都会泄漏,直到另一个编辑文本聚焦为止。
你怎么能解决这个问题?遗憾的是,这是SDK代码,所以虽然这可能会在LG的未来版本中修复,但总会有一些用户遇到该错误。
虽然这个错误肯定不是你的错,但它仍然是内存泄漏,它可能泄漏到增加的OutOfMemory错误。所以,值得尝试解决它,
有一种方法,但它并不漂亮。当活动被销毁时,您可以使用反射来清除泄漏。例如,一种方法可能是清除sHelper字段,或另一种方法是清除帮助程序上的mView字段。无论哪种方式,你应该在设备上尝试(我现在没有它),看看它是否有效。
private static final Executor backgroundExecutor =
newCachedThreadPool(backgroundThreadFactory("android-leaks"));
public static void fixLGBubblePopupHelper(final Application application) {
backgroundExecutor.execute(new Runnable() {
@Override public void run() {
final Field sHelperField;
try {
Class<?> bubbleClass = Class.forName("android.widget.BubblePopupHelper");
sHelperField = bubbleClass.getDeclaredField("sHelper");
sHelperField.setAccessible(true);
} catch (Exception ignored) {
// We have no guarantee that this class / field exists.
return;
}
application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
try {
sHelperField.set(null, null);
} catch (IllegalAccessException ignored) {
}
}
});
}
});
}