由于android.widget.BubblePopupHelper导致的内存泄漏

net*_*men 5 android memory-leaks

我正在使用MemoryAnalyzer工具在我的Android应用程序中查找内存泄漏.所以我运行我的应用程序,访问所有活动,然后按回去,直到我到达桌面.然后我使用DDMS来获取内存转储(已经多次按下Cause GC).

然后我使用OQL查询select * from instanceof android.app.Activity来查找泄漏活动,然后按下Merge Shortest Path to GC Roots - >排除泄漏对象上的所有幻像/弱/软/等参考.在这里,我有这张照片:

在此输入图像描述

所以系统中的某个地方似乎有一个静态对象BubblePopupHelper.sHelper,它保留了对EditText我活动视图的引用,导致整个活动泄漏!但这是什么BubblePopupHelper?我在官方文档中找不到关于此课程的任何信息.如何防止我的活动由于被这个奇怪的对象引用而被保留在内存中?

我在LG L40设备上测试,运行API19

Pie*_*cau 9

我的泄漏检测工具定期报告相同的泄漏,仅来自LG手机:

object com.squareup.SomeActivity
`-mContext of object android.widget.EditText
  `-mView of object android.widget.BubblePopupHelper
    `-sHelper of class android.widget.BubblePopupHelper
Run Code Online (Sandbox Code Playgroud)

制造商喜欢在幕后更改Android SDK的私有API.这是LG引入的内存泄漏.

从我可以收集到的,焦点的EditText使用BubblePopupHelper,可能显示一些复制/粘贴弹出窗口或文本句柄.由于一次只有一个聚焦编辑文本,因此他们使帮助者成为单例,并且它保留了对最新编辑文本的引用.

这意味着整个Activity及其整个视图层次结构将泄漏,直到另一个编辑文本被聚焦.

你怎么解决这个问题?遗憾的是,这是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) {
          }
        }
      });
    }
  });
}
Run Code Online (Sandbox Code Playgroud)