安卓应用内存分析——《Memory Analysis for Android Applications》

Dalvik虚拟机有垃圾回收机制,但这并不意味着你可以忽略内存管理。尤其要注意在内存严重受限的移动设备上的内存用法。在这篇文章中,我们会一起来看一看AndroidSDK中的内存

分析工具,以帮助你优化程序内存用量。

 一些内存使用的问题是非常明显的。比如,如果你的APP在被用户使用的任何时候泄露了内存,都可能会导致OutOfMemoryError,最终导致你的程序奔溃。其他的一些问题更微妙、不易察觉,可能是降低程

序(当垃圾回收器更频繁调用且花费更长时间)或系统性能。

 

工具使用

 

Android SDK提供了两种分析APP内存使用的方法:

DDMS中的Allocation Tracker标签

heap dumps(堆转储)

 

当你想获得在特定的时期哪些分配内存的行为正在发生,但又没有给你程序堆的整体信息时,Allocation Tracker就非常有用了。获取更多关于Allocation Tracker的信息请看文章:

 TrackingMemory Allocations本文的其余部分主要关注heap dumps——一个功能强大的内存分析工具。

 

Heap dump(堆垃圾场)是一个被存储在二进制格式的HPROF文件中的应用程序堆的快照。Dalvik使用的与HPROF tool in Java的格式相似,但又不完全相同。有一些生成正在运行的Android程序的heapdump的方法。

第一种是使用在DDMS试图中的Dump HPROF file按钮。如果你需要当dump被创建时更精确的信息,你也可以用

 android.os.Debug.dumpHprofData()功能编程,创建一个heap dump



分析heap dump时,你可以使用像jhat或者Eclipse Memory Analyzer (MAT).这样的基础工具。无论如何,第一次你都需要将Dalvik格式的.hprof文件转换成J2SE  HPROOF格式。你可以使用Android SDK下的“hprof-conv”工具完成这项工

作。例如:

 

hprof-convdump.hprofconverted-dump.hprof

 

举个例子:调试内存泄露

 

Dalvik运行时,开发者不能明确地分配和释放内存。因此,你不能像CC++那样泄露内存。在你的代码中”内存泄露“是当你持有一个不再需要的对象的引用。有时,一个单一的引用能够预防大量的对象被垃圾回收。

 

让我们通过一个SDK中的HoneycombGallery sample app例子来试验一下。他是一个演示如何使用一些新的Honeycomb APIs的简单的画廊应用。我们故意在其中加入可以造成内存泄露的代码。


 

想象一下,当我们从网络获取图片,为了使它更加流畅,我们可能决定实现一个图片缓存器。我们对ContentFragment.java文件做了一些小改动。在类的顶端,加入一个新的静态变量

privatestaticHashMap<String,Bitmap> sBitmapCache =newHashMap<String,Bitmap>();

这就是我们的Bitmap缓存。现在我们可以修改updateContentAndRecyleBitmap()方法在加载之前检查cache,同时在加载完成后添加Bitmapscache

void updateContentAndRecycleBitmap(int category, int position) {
    if (mCurrentActionMode != null) {
        mCurrentActionMode.finish();
    }
 
    // 获取需要绘制和更新到ImageView的Bitmap(Get the bitmap that needs to be drawn and update the ImageView.)
 
    // 检查这个Bitmap是否已经在cache中存在(Check if the Bitmap is already in the cache)
    String bitmapId = "" + category + "." + position;
    mBitmap = sBitmapCache.get(bitmapId);
 
    if (mBitmap == null) {
        // 不在cache中,因此加载Bitmap并将其加入到cache。(It's not in the cache, so load the Bitmap and add it to the cache.)
        //注意!我们向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);
}

我们在这里如意引入了一个内存泄漏:添加Bitmapcache但没有移除任何对象。在一个真实的APP中,我们可能会限制缓存的大小。

  

DDMS检查heap

 

The Dalvik Debug Moniter Server(DDMS)是初级的Android调试工具之一,是ADT插件的一部分,独立版本可以在SDKtools/ directory目录找到。更多关于DDMS的信息,见UsingDDMS

 

让我们用DDMS来检查这个APPheap。你可以通过以下两种方式启动DDMS

1from Eclipse: click Window > Open Perspective > Other... >DDMS

2from the commandline: run ddms (or ./ddms on Mac/Linux) in the tools/ directory


在左边面板上选中om.example.android.hcgallery进程,然后点击工具栏上的“show heap updates”按钮。然后切换到DDMS中的“VM Heap”标签。它显示了每一次GC后,程序内存使用的一些基本的统计信息。看第一个更新,点击“Cause GC”按钮。

创建一个Heap Dump


让我们用Heap Dump来跟踪这个问题。点击DDMS工具条上的“Dump HPROF file”按钮,选择你想存放文件的位置,然后运行“hprof-conv”。在这个例子中,我将使用基础版本的MATversion 1.0.1)。MAT download site

如果你正在运行ADT,且它安装了MAT插件,点击“Dump hprof”按钮,会自动转换(执行hprof-conv),同时自动在Eclipse中打开转换后的hprof文件(用MAT打开)。


用MAT工具分析Heap dumps


启动MAT,加载转换好的hprof文件。MAT是一个强大的工具,解释它的功能超出了本文的范围。因此我只要告诉一个你可以用来检测泄露的方法——直方图

直方图显示了一个按照实例(instance)数量排序的列表,“浅堆(shallow heap----所有实例使用的内存总量”或者“保留堆(retained heap---所有实例的保留的内存总量,包括他们引用的其他对象”。


如果我们按照浅堆排序,我们能看到byte[]的实例在顶部。在Android3.0Bitmap的像素数据对象被存在byte数组中(先前它没有存在Dalvik堆中),并根据这些对象的大小,可以肯定,Bitmap导致内存泄露了。(根据上面的图说的,不是所有的Bitmap都会导致内存泄露)

 

  • 右击这个byte[]——》选择“List Object>with incoming reference”。这可以列出heap中我们可以按照shallow heap用量排序的所有byte数组。

 

  • 选取一个大的对象,深入(一层层展开)。他会向你显示对象的根据经——一直维持着这个对象的链。Lo and behold(你瞧!)他就是我们的Bitmap Cache

MAT不能肯定地告诉我们它泄露了,因为他不知道是否需要这些对象——只有开发者知道。这个cache使用了相对应用其他地方来说较多的内存,所以我们考虑限制它的大小。


用MAT比较Heap dumps


当调试内存泄露时,在两个不同的时间点比较Heap信息是很有用的。这样做,你需要创建两个独立的hprof文件(不要忘记用hpfor-conv工具转换他们)。

 

以下是你如何在MAT比较两个Heap dumps(有一点点复杂):

1、打开第一个HPROF文件(usingFile > Open Heap Dump).

2、打开柱状图。

3、在导航历史视图(use Window>Navigation History 如果它不可见),在主张图上右击,选择“Add to Compare Basket”。

4、打开第二个HPROF文件并重复步骤2和步骤3.

5、切换到“Compare Basket view”,点击“Compare the Results”)(顶部角落的红色“”图标)


 结论


在这篇文章中,我展示了Allocation TrackerHeap dumps如何能让你的应用程序安全的使用内存。也演示了MAT检查你APP中的内存泄露。MAT是一个强大的工具,我只向你展示了冰山一角。如果你想了解更多,推荐你读一些文章:



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值