哪些 Android 工具和方法最适合查找内存/资源泄漏?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1147172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:44:38  来源:igfitidea点击:

What Android tools and methods work best to find memory/resource leaks?

androidmemory-leaks

提问by jottos

I've got an Android app developed, and I'm at the point of a phone app development where everything seems to be working well and you want to declare victory and ship, but you know there just have to be some memory and resource leaks in there; and there's only 16mb of heap on the Android and its apparently surprisingly easy to leak in an Android app.

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

I've been looking around and so far have only been able to dig up info on 'hprof' and 'traceview' and neither gets a lot of favorable reviews.

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

What tools or methods have you come across or developed and care to share maybe in an OS project?

您在操作系统项目中遇到或开发过哪些工具或方法并愿意分享?

回答by hp.android

One of the most common errors that I found developing Android Apps is the “java.lang.OutOfMemoryError: Bitmap Size Exceeds VM Budget” error. I found this error frecuently on activities using lots of bitmaps after changing orientation: the Activity is destroyed, created again and the layouts are “inflated” from the XML consuming the VM memory avaiable for bitmaps.

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

Bitmaps on the previous activity layout are not properly deallocated by the garbage collector because they have crossed references to their activity. After many experiments I found a quite good solution for this problem.

垃圾收集器没有正确释放先前活动布局上的位图,因为它们已经交叉引用了它们的活动。经过多次实验,我找到了一个很好的解决这个问题的方法。

First, set the “id” attribute on the parent view of your XML layout:

首先,在 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"
     >
     ...

Then, on the onDestroy() method of your Activity, call the unbindDrawables() method passing a refence to the parent View and then do a System.gc()

然后,在您的 Activity 的 onDestroy() 方法上,调用 unbindDrawables() 方法,将引用传递给父视图,然后执行 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();
    }
}

This unbindDrawables() method explores the view tree recursively and:

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

  1. Removes callbacks on all the background drawables
  2. Removes childs on every viewgroup
  1. 删除所有背景可绘制对象的回调
  2. 删除每个视图组上的子项

回答by Timo Ohr

Mostly for Google travelers from the future:

主要面向未来的 Google 旅行者:

Most java tools are unfortunately unsuitable for this task, because they only analyze the JVM-Heap. Every Android Application also has a native heap, though, which also has to fit within the ~16 MB limit. It's usually used for bitmap data, for example. So you can run quite easily into Out Of Memory errors even though your JVM-Heap is chillin around 3 MBs, if you use a lot of drawables.

遗憾的是,大多数 Java 工具不适合此任务,因为它们只分析 JVM-Heap。不过,每个 Android 应用程序也有一个本机堆,它也必须在 ~16 MB 的限制范围内。例如,它通常用于位图数据。因此,如果您使用大量可绘制对象,即使您的 JVM 堆只有 3 MB 左右,您也很容易遇到内存不足错误。

回答by darrenp

The answer from @hp.android works well if you are just working with bitmap backgrounds but, in my case, I had a BaseAdapterproviding a set of ImageViews for a GridView. I modified the unbindDrawables()method as advised so that the condition is:

从@ hp.android答案运作良好,如果你只是用位图背景的工作,但是,在我的情况,我有一个BaseAdapter提供一组ImageView为A S GridView。我unbindDrawables()按照建议修改了方法,以便条件为:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

but the problem then is that the recursive method never processes the children of the AdapterView. To address this, I instead did the following:

但问题是递归方法从不处理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();
}

so that the children of the AdapterVieware still processed -- the method just doesn't attempt to remove all children (which is unsupported).

以便AdapterView仍然处理的孩子- 该方法只是不尝试删除所有孩子(这是不受支持的)。

This doesn't quite fix the problem however since ImageViews manage a bitmap that is not their background. I therefore added the following. It's not ideal but it works:

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

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

Overall the unbindDrawables()method is then:

总的来说,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();
  }
}

I'm hoping there is a more principled approach to freeing up such resources.

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

回答by greg7gkb

Good Google I/O talk (2011) on Memory Management in Android, as well as details on tools + techniques for memory profiling:
http://www.youtube.com/watch?v=_CruQY55HOk

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

回答by jww

Valgrind has been ported to Android (sponsored by Mozilla). See Valgrind on Android — Current Statusand Support Running Valgrind for Android on ARM(comment 67).

Valgrind 已被移植到 Android(由 Mozilla 赞助)。请参阅Android 上的 Valgrind — 当前状态支持在 ARM 上运行 Valgrind for Android(评论 67)。

回答by Fred Grott

Well, those are the tools that hook with the unique formats that Android uses..I think what you may be unsatisfied with is the underlying testing code framework in use..

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

Have you tried mock testing areas of code using the Android Mock Framework?

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