哪些Android工具和方法最有效地查找内存/资源泄漏?

时间:2009-07-18 10:10:57

标签: android memory-leaks

我已经开发了一个Android应用程序,而且我正处于手机应用程序开发阶段,其中一切似乎都运行良好,你想宣布胜利和发货,但你知道必须有一些记忆和资源泄漏; Android上只有16mb的堆,而且在Android应用程序中显然很容易泄漏。

我一直在环顾四周,到目前为止我们只能挖掘'hprof'和'traceview'的信息,而且没有得到很多好评。

您遇到或开发了哪些工具或方法,并且可能需要在OS项目中共享?

7 个答案:

答案 0 :(得分:90)

我发现开发Android应用程序时最常见的错误之一是“java.lang.OutOfMemoryError:Bitmap Size Exceeds VM Budget”错误。在更改方向后,我在使用大量位图的活动中发现了这个错误:活动被销毁,再次创建,布局从消耗可用于位图的VM内存的XML中“膨胀”。

垃圾收集器未正确释放先前活动布局上的位图,因为它们已经交叉引用了它们的活动。经过多次实验,我发现了一个很好的解决方案。

首先,在XML布局的父视图上设置“id”属性:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

然后,在Activity的onDestroy()方法中,调用unbindDrawables()方法将refence传递给父View,然后执行System.gc()

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}


private void unbindDrawables(View view) {

    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }

    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }

        ((ViewGroup) view).removeAllViews();
    }
}

这个unbindDrawables()方法以递归方式探索视图树:

  1. 删除所有背景drawable上的回调
  2. 删除每个视图组中的子项

答案 1 :(得分:29)

答案 2 :(得分:28)

主要针对未来的Google旅行者:

遗憾的是,大多数java工具都不适用于此任务,因为它们只分析JVM-Heap。但是,每个Android应用程序也都有一个本机堆,它也必须符合~16 MB的限制。例如,它通常用于位图数据。所以你可以很容易地运行Out Of Memory错误,即使你的JVM-Heap是大约3 MB的chillin,如果你使用了大量的drawables。

答案 3 :(得分:20)

如果您只使用位图背景,@ hp.android的答案效果很好,但在我的情况下,我有BaseAdapter为{{1}提供一组ImageView s }。我按照建议修改了GridView方法,以便条件为:

unbindDrawables()

但问题是递归方法永远不会处理if (view instanceof ViewGroup && !(view instanceof AdapterView)) { ... } 的子节点。为了解决这个问题,我改为做了以下几点:

AdapterView

以便仍然处理if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) unbindDrawables(viewGroup.getChildAt(i)); if (!(view instanceof AdapterView)) viewGroup.removeAllViews(); } 的子项 - 该方法不会尝试删除所有子项(不受支持)。

这并不能解决问题,因为AdapterView管理的位图不是他们的背景。因此,我添加了以下内容。它并不理想但它有效:

ImageView

总的来说,if (view instanceof ImageView) { ImageView imageView = (ImageView) view; imageView.setImageBitmap(null); } 方法是:

unbindDrawables()

我希望有一种更有原则的方法来释放这些资源。

答案 4 :(得分:12)

关于Android内存管理的良好Google I / O演讲(2011),以及有关内存分析的工具+技术的详细信息:
http://www.youtube.com/watch?v=_CruQY55HOk

答案 5 :(得分:4)

Valgrind已被移植到Android(由Mozilla赞助)。请参阅Valgrind on Android — Current StatusSupport Running Valgrind for Android on ARM(评论67)。

答案 6 :(得分:1)

嗯,这些是与Android使用的独特格式相关联的工具。我认为您可能不满意的是正在使用的基础测试代码框架。

您是否尝试使用Android Mock Framework模拟测试代码区域?