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

153

我开发了一个Android应用程序,现在应用程序看起来运行良好,你想要宣布胜利并发布App,但你知道其中肯定存在一些内存和资源泄漏问题;而且在Android上只有16MB的堆空间,很容易在Android应用程序中出现泄漏问题。

我一直在寻找解决方法,目前只能找到关于“hprof”和“traceview”的信息,但这两种工具都没有得到太多好评。

您是否遇到过其他工具或方法,并且能够分享一些在OS项目中使用的经验?


3
我可以投票让Р̀СТȢѸ́ФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ改成一个可读的人类名字吗? - JPM
1
如果我们从问题标题中删除“Android工具”这个词,重新打开这个问题是否可以?在这里找到的答案对解决我的内存泄漏问题非常有用。 - k3b
好的,我有一个用户不断在活动之间切换,这意味着他们可能在20秒内切换了15个活动。这可能会导致内存错误吗?我该怎么做才能解决它?谢谢! - Ruchir Baronia
1
无法提供此响应,因为问题已关闭,但我建议查看Leak Canary。只需使用您的应用程序,打开和关闭活动,让库完成其工作即可。它甚至会告诉您泄漏发生的位置。在泄漏发生后,请给泄漏分析器一些时间来完成其工作-通常需要大约2分钟或更长时间才能找到泄漏源。之后,它将在应用程序中整洁地呈现给您。无需额外的工具! - ubuntudroid
6个回答


28

主要适用于未来的Google旅行者:

大多数Java工具不幸地不能胜任此任务,因为它们只分析JVM堆。然而,每个Android应用程序也有本机堆,这也必须适合约16MB的限制。通常用于位图数据,例如。因此,即使您的JVM堆大小在3MB左右,如果使用了大量可绘制对象,您很容易遇到内存不足错误。


6
从Android 3.0(蜂巢)开始,可绘制对象存储在堆中。 - Gu1234
@Timo那你会用什么来检测本地堆中的泄漏呢? - sydd
1
测试,大量的测试。问题在于,由于内存共享和其他优化技术,您甚至无法真正确定应用程序使用了多少内存。您可以使用常规的 shell 命令获取内存读数,但那些只是非常粗略的估计。 - Timo Ohr

20

@hp.android的答案在您只是使用位图背景时效果很好,但在我的情况下,我有一个BaseAdapter为GridView提供一组ImageView。 我按建议修改了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()方法如下:

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();
  }
}

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


12

4
或者对应的博客文章:http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html - greg7gkb
1
好的,我有一个用户不断在活动之间切换,这意味着他们可能在20秒内切换了15个活动。这可能是导致内存错误的原因吗?我该怎么做才能解决它?谢谢! - Ruchir Baronia

4

需要构建定制 ROM 才能实现。 - Akshat

1

好的,这些是与Android使用的独特格式相连接的工具..我认为你可能对使用的基础测试代码框架不满意..

你尝试过使用Android Mock Framework模拟测试代码区域吗?


1
不是这样的,那种测试并不是问题的关键,而是记录应用程序运行时实际发生的情况。我真正需要的是一种资源/内存泄漏分析工具。 - jottos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接