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

jot*_*tos 151 android memory-leaks

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

我一直在环顾四周,到目前为止只能找到关于'hprof'和'traceview'的信息并且没有得到很多好评.

您在OS项目中遇到或开发并关心分享哪些工具或方法?

hp.*_*oid 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"
     >
     ...
Run Code Online (Sandbox Code Playgroud)

然后,在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这不适用于AdapterView(ListView,GridView等)的子类. (9认同)
  • @Jackson只是改变了条件:if(查看实例ViewGroup &&!(查看instanceof AdapterView))这将消除你为Adapter获取的异常 (4认同)
  • 解决常见问题的好方法. (3认同)

Tim*_*Ohr 28

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

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

  • 启动Android 3.0(蜂窝)drawables存储在堆中 (6认同)

dar*_*enp 20

如果您只是处理位图背景,@ hp.android的答案效果很好,但在我的情况下,我BaseAdapter提供了一组ImageViews用于a GridView.我unbindDrawables()按照建议修改了方法,以便条件是:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

但问题是,递归方法永远不会处理孩子的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();
}
Run Code Online (Sandbox Code Playgroud)

以便AdapterView仍然处理子的 - 该方法不会尝试删除所有子项(不受支持).

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

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}
Run Code Online (Sandbox Code Playgroud)

总的来说,unbindDrawables()方法是:

private void unbindDrawables(View view) {
  if (view.getBackground() != null)
    view.getBackground().setCallback(null);

  if (view instanceof ImageView) {
    ImageView imageView = (ImageView) view;
    imageView.setImageBitmap(null);
  } else 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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


gre*_*gkb 12

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

  • 或相应的博客文章:http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html (4认同)

Fre*_*ott 1

嗯,这些都是与 Android 使用的独特格式挂钩的工具。我认为您可能不满意的是正在使用的底层测试代码框架。

您是否尝试过使用 Android Mock 框架来模拟测试代码区域?