android应用内存分析,Android应用程序内存分析-Memory Analysis for Android Applications

Android应用程序内存分析

原文链接:http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html

Dalvik 自带有内存回收机制,但这并不意味程序员可以忽略内存的管理。在移动设备上,内存比较紧缺,因此你应当对内存的使用更加小心。在本文中,我们将介绍如何使用android SDK中的内存分析工具来对应用程序的内存使用情况进行分析。

有些内存问题是显而易见的。例如,如果应用程序在每次用户触摸屏幕时都会泄漏一些内存,那么该应用将很快因为 OutOfMemoryError的异常而崩溃。另外一些则更加隐蔽,它们有可能只会导致应用程序和整个系统变慢(垃圾回收器频繁和长时间进行垃圾回收)

调试工具

在android SDK中提供了两种内存分析的方法:内存申请跟踪(以下用Allocation tracker) 和 堆转储(以下用heap dump)。Allocation tracker可以帮我们了解到一段时间内,应用对内存的申请情况,但是它不能提供任何有关应用程序堆的信息。更多有关内存申请追踪的信息请看 Tracking Memory Allocations。接下来的篇幅中我们将重点关注一种更加强有力的分析工具——heap dump的使用。

Heap dump是应用程序堆的的快照,它存放在一种特定格式(HPROF)的二进制文件中。Dalvik使用类似于HPROF的格式来保存heap dump。生成应用程序的heap dump的方法有多种,DDMS中的head dump按钮就提供了生成heap dump的功能。如果想要对heap dump的生成有更加精细的控制,可以在程序中使用android.os.Debug.dumpHprofData()来生成。

常用的分析heap dump的工具有jhat 和 Eclipse Memory Analyzer (MAT) 。在分析之前,我们需要将Dalivk heap dump文件的格式转换成J2SE 标准的HPROF格式。android SDK中提供了hprof-conv工具来进行这个转换。命令如下:

hprof-conv dump.hprof converted-dump.hprof

例子:如何分析内存泄漏

在Dalivk环境中,程序员不能显式的申请和释放内存,因此内存不会像在C/C++中的那样真正泄漏。在这种情况下,内存泄漏往往指的是程序中保存了无用的对象的引用,有时保存一个对象的引用,而这个对象又拥有大量其他对象的引用,那么这些对象将都无法被垃圾回收器回收。

让我们看android SDK中的一个示例程序Honeycomb Gallery sample app。这是一个用来展示如何使用android Honeycomb 中的新API的照片库应用(如何下载和编译这个应用的代码,请看介绍)。我们将小心的在这个应用的代码中加入一个内存泄漏的bug,以讲述如何调试这样的问题。

假如我们想修改这个应用,让其具有从网络上下载图片的能力。为了提升体验,我们决定实现一个缓存以存储最近收到的图片,我们通过对ContentFragment.java文件进行一些小的修改来实现这个想法。首先在这个类的顶部加上一个静态的变量

private static HashMapsBitmapCache = new HashMap();

这个变量将保存我们想要缓存的图片,现在我们修改updateContentAndRecycleBitmap() 加入检查存储和存入缓存的功能

void updateContentAndRecycleBitmap(int category, int position) {

if (mCurrentActionMode != null) {

mCurrentActionMode.finish();

}

// Get the bitmap that needs to be drawn and update the ImageView.

// Check if the Bitmap is already in the cache

String bitmapId = "" + category + "." + position;

mBitmap = sBitmapCache.get(bitmapId);

if (mBitmap == null) {

// It's not in the cache, so load the Bitmap and add it to the cache.

// DANGER! We add items to this cache without ever removing any.

mBitmap = Directory.getCategory(category).getEntry(position)

.getBitmap(getResources());

sBitmapCache.put(bitmapId, mBitmap);

}

((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap);

}

这里,我故意留下了一个memory leak的问题:我们将Bitmap添加到cache但是却从来不从cache中删除它们。在真正的应用中,往往会对cache的大小进行一个限制。

使用DDMS来分析内存使用情况

DDMS是android最主要的一个调试工具,它是ADT插件的一部分,同时在android SDK的tools/ directory目录下也有一个独立的版本。更对关于DDMS的信息,请看Using DDMS

让我们使用DDMS来分析内存使用情况。DDMS有两种启动方式:

从Eclipse:点击Window > Open Perspective > Other... > DDMS

从命令行:在tools/ directory中执行ddms命令

a4f30c61a9a5978cac4fee3b273f1afe.png

在左边的面板里选择进程com.example.android.hcgallery,然后点击工具栏上的Show heap updates按钮,之后切换到DDMS中的VM Heap页。这里显示了堆内存的基本状态信息,这些信息每次GC时更新。点击Cause GC按钮可以触发第一次更新。

3798cf8405f5e9b15fd6675ddaa70478.png

可以看到,我们使用了8MB多一点的内存,现在滑动相册,看到这个数字会变大。由于应用中总共只有13張图片,因此我们不会无限制的泄漏内存。从某种意义上来说,这是一种最糟糕的泄漏,因为我们永远也不会收到OutOfMemoryError的异常来帮助我们发现这个问题。

创建一个heap dump

让我们使用heap dump来定位这个问题。点击中DDMS工具栏上的Dump HPROF按钮,选择一个保存路径,然后运行hprof-conv处理这个文件。在这个例子中,我将使用MAT的独立应用版本(版本号1.0.1),下载链接MAT download site

如果你正在使用ADT并且Eclipse中已经安装了MAT插件,点击dump HPROF按钮,工具将会自动对HPROF文件进行格式转换,然后直接在Eclipse中使用MAT打开转换后的HPROF文件。

使用MAT分析heap dump

启动MAT,打开我们转换过的HPROF文件。MAT是个强大的工具,拥有很多功能。在这篇文章中,我只介绍一种使用它来分析内存问题的方法:Histogram view。Histogram view显示了堆中所有类的列表,我们可以将列表中这些类按照其实例(object)的个数的多少排序(包括按照浅堆中实例的个数和深堆中实例的个数)

566b44c6c86c7119b4ea58b8a7d7d801.png

如果我们按照浅堆排序,我们可以看到byte[]类型排在第一位,这是因为在android3.0中bitmap的像素点数据都保存在byte数组中(之前它们都没有被保存在dalik的堆空间中),基于这些数组的大小,我们可以断言,这些数组就是我们泄漏的bitmap内存的一部分。

在列表中右击byte[]类型,在弹出菜单中依次选择List Objects > with incoming references,可以看到,在之前视图中我们点击的类型对应的所有浅堆中的byte array对象都被列了出来。

选择其中一个比较大的对象,点击箭头查看下拉列表中的内容,这里我们可以看到这个对象的整条引用链,其中可以找到我们的bitmap cache。

044838ee181fc883a4d483864fa648e7.png

MAT不能明确的告诉我们哪里发生了泄漏,因为它并不知道这些对象是否还在使用——仅仅只有程序员知道这一点。在这个例子中,缓存占用了应用程序大量的内存,因此在这种情况下,我们应该考虑对cache的大小进行限制。

使用MAT对heap dump进行比较

有时比较两个不同时间点的heap dump对我们分析内存泄漏问题是很有帮助的。首先,我们需要生成两个heap dump文件(别忘记使用 hprof-conv进行转换)

接下来我们可以使用MAT进行比较了(过程稍稍有些复杂)

打开第一个HPROF 文件(使用 File > Open Heap Dump)

打开Histogram view

在Navigation History view中(如果找不到使用 Window > Navigation History打开), 对其中的histogram条目右击,然后选择Add to Compare Basket.

重复2~3步骤,打开第二个HPROF文件

切换到Compare Basket 页,点击Compare the Results按钮(这页右上角的红色按钮)

总结

在本文中,我展示了如何通过Allocation Tracker 和 heap dumps 这两个工具来

更好的认识

应用内存的使用情况有。我也展示了如何使用MAT来追踪应用中的内存泄漏问题。MAT是个强大的工具,而我在这里仅仅只是提到了它的皮毛。如果你想要了解更多相关内容,我建议你阅读下面的文章

Memory Analyzer News: Eclipse MAT官方blog

Markus Kohler 的java性能分析博客有很多有用的文章, 包括 Analysing the Memory Usage of Android Applications with the Eclipse Memory Analyzer 和10 Useful Tips for the Eclipse Memory Analyzer.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值