`

Android应用程序的内存分析

阅读更多

Dalvik虚拟机支持垃圾收集,但是这不意味着你可以不用关心内存管理。你应该格外注意移动设备的内存使用,在上面内存空间是受到限制的。在这篇 文章里面,我们来看看Android SDK里面的一些内存剖析工具(profiling tools)是如何帮助我们修整应用程序的内存使用。

一些内存使用问题是很明显的,例如,如果在每次用户触摸屏幕的时候应用程序有内存泄露,将会有可能触发OutOfMemoryError,最终程序崩溃。另外一些问题却很微妙,也许只是降低应用程序和整个系统的性能(当高频率和长时间地运行垃圾收集器的时候)。

必要的工具:

Android SDK提供了2个主要的剖析应用程序内存使用情况的工具:DDMS里的一个分页Allocation Tracker和heap dumps。Allocation Tracker是很有用的,特别是当你想得到程序在一定的时间里内存的分配情况的一种感性认识的时候。但是它不能给你任何关于程序heap总体情况的任何 信息。关于Allocation Tracker的更多信息,请看文章Tracking Memory Allocations 。文章剩下的内容将把重点放在heap dumps,它是更强大的内存分析工具。


一个heap dump就是一个程序heap的快照,它保存为一种叫做HPROF的二进制格式。Dalvik用的也是类似的格式,但是不完全一样。这里是Java的HPROF工具 。有很多方法去生成一个运行时应用程序的heap dump。其中一种就是使用在DDMS里边的Dump HPROF file按钮。如果想产生更精确的dump数据,可以在程序中使用android.os.Debug.dumpHprofData() 方法。

分析heap dump,你可以使用一些标准的工具比如jhat 或者Eclipse Memory Analyzer(MAT) 。不过,首先你需要把.hprof文件从Dalvik格式转换成J2SE HPROF格式。你可以使用Android SDK提供的hprof-conv工具。例如:

  1. hprof-conv dump.hprof converted-dump.hprof  

调试一个内存泄露实例:


在Dalvik运行时里边,程序员不能显式地分配和释放内存,所以这里的内存泄露跟c和c++里面的不同。在你的代码里边,内存泄露就是你保留了一个并不再需要的类对象的引用。有时候仅仅一个引用就会阻碍gc对一大堆对象的回收。

我们来过一个实际的例子,Android SDK里面提供的范例程序Honeycomb Gallery sample app 。它是一个photo gallery程序,用来演示一些新的Honeycomb API的使用。(下载和编译这些代码,请看这些命令 。)我们会有意地加入一个内存泄露在程序里边,然后来演示如何调试它。

 
想象一下我们想修改程序让它从网络下载图片。为了让它更具备灵活性,我们可以考虑实现一个缓存,保存最近查看过的图片。我们可以对ContentFragment.java做一些小的修改来达到这个目的。在class顶部,我们增加一个新的静态变量:

  1. private   static  HashMap<String,Bitmap> sBitmapCache =  new  HashMap<String,Bitmap>();  

这里就是我们保存缓存的地方。现在我们可以修改updateContentAndRecycleBitmap()方法,让它在下载之前先查看是否数据已经存在,如果不存在就去下载,然后添加数据到缓存。

  1. void  updateContentAndRecycleBitmap( int  category,  int  position) {  
  2.     if  (mCurrentActionMode !=  null ) {  
  3.         mCurrentActionMode.finish();  
  4.     }  
  5.    
  6.     // Get the bitmap that needs to be drawn and update the ImageView.   
  7.    
  8.     // Check if the Bitmap is already in the cache   
  9.     String bitmapId = ""  + category +  "."  + position;  
  10.     mBitmap = sBitmapCache.get(bitmapId);  
  11.    
  12.     if  (mBitmap ==  null ) {  
  13.         // It's not in the cache, so load the Bitmap and add it to the cache.   
  14.         // DANGER! We add items to this cache without ever removing any.   
  15.         mBitmap = Directory.getCategory(category).getEntry(position)  
  16.                 .getBitmap(getResources());  
  17.         sBitmapCache.put(bitmapId, mBitmap);  
  18.     }  
  19.     ((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap);  
  20. }  

我已经在这里故意引入了一个内存泄露的问题:我们把图片加入了缓存但是从来没有移除他们。在真实的应用里,我们可以会用某种方法来限制缓存的大小。

 

在DDMS里检查heap的使用情况

 

Dalvik Debug Monitor Server(DDMS)是主要的Android调试工具之一,也是ADT Eclipse plug-in 的一部分,独立的程序版本也可以在Android SDK的根目录下的tools/下面找到。关于DDMS更多的信息,请参考使用DDMS

 

我们来使用DDMS检查这个应用的heap使用情况。你可以使用下面的两种方法启动DDMS:

  • from Eclipse: click Window > Open Perspective > Other... > DDMS
  • or from the command line: run ddms (or ./ddms on Mac/Linux) in the tools/ directory

 

在左边的面板选择进程com.example.android.hcgallery,然后在 工具条上边点击Show heap updates按钮。这个时候切换到DDMS的VM Heap分页。它会显示每次gc后heap内存的一些基本数据。要看第一次gc后的数据内容,点击Cause GC按钮:

 

 

我们可以看到现在的值(Allocated列)是有一些超过8MB。现在滑动相片,这时看到 数据在增大。因为只有仅仅13个相片在程序里边,所以泄露的内存只有这么大。在某种程度上来说,这时最坏的一种内存泄露,因为我们没法得到 OutOfMemoryError来提醒我们说现在内存溢出了。

 

生成heap dump

 

我们现在使用heap dump来追踪这个问题。点击DDMS工具条上面的Dump HPROF文件按钮,选择文件存储位置,然后在运行hprof-conv。在这个例子里我们使用独立的MAT版本(版本1.0.1),从MAT站点下载

 

如果你使用ADT(它包含DDMS的插件)同时也在eclipse里面安装了MAT,点击“dump HPROF”按钮将会自动地做转换(用hprof-conv)同时会在eclipse里面打开转换后的hprof文件(它其实用MAT打开)。

 

用MAT分析heap dumps

启动MAT然后加载刚才我们生成的HPROF文件。MAT是一个强大的工具,讲述它所有的特性超出了本文的范围,所以我只想演示一种你可以用来检测 泄露的方法:直方图(Histogram)视图。它显示了一个可以排序的类实例的列表,内容包括:shallow heap(所有实例的内存使用总和),或者retained heap(所有类实例被分配的内存总和,里面也包括他们所有引用的对象)。

 

如果我们按照shallow heap排序,我们可以看到byte[]实例在顶端。自从Android3.0(Honeycomb),Bitmap的像素数据被存储在byte数组里 (之前是被存储在Dalvik的heap里),所以基于这个对象的大小来判断,不用说它一定是我们泄露掉的bitmap。

 

右击byte[]类然后选择List Objects > with incoming references。它会生成一个heap上的所有byte数组的列表,在列表里,我们可以按照Shallow Heap的使用情况来排序。

 

选择并展开一个比较大的对象,它将展示从根到这个对象的路径--就是一条保证对象有效的链条。注意看,这个就是我们的bitmap缓存!

 

MAT不会明确告诉我们这就是泄露,因为它也不知道这个东西是不是程序还需要的,只有程序员知道。在这个案例里面,缓存使用的大量的内存会影响到后面的应用程序,所以我们可以考虑限制缓存的大小。

 

使用MAT比较heap dumps

 

调试内存泄露时,有时候适时比较2个地方的heap状态是很有用的。这时你就需要生成2个单独的HPROF文件(不要忘了转换格式)。下面是一些关于如何在MAT里比较2个heap dumps的内容(有一点复杂):

  1. 第一个HPROF 文件(using File > Open Heap Dump ).
  2. 打开 Histogram view.
  3. 在Navigation History view里 (如果看不到就从Window > Navigation History找 ), 右击histogram 然后选择Add to Compare Basket .
  4. 打开第二个HPROF 文件然后重做步骤2和3.
  5. 切换到Compare Basket view, 然后点击Compare the Results (视图右上角的红色"!"图标)。

总结

这本篇文章里面,我展示了Allocation Tracker和heap dumps是如何给你一种对程序内存使用的感性认识。我也展示了Eclipse Memory Analyzer(MAT)可以帮助追逐我们程序里面的内存泄露问题。MAT是一个强大的工具,我也仅仅触碰了一些皮毛,如果你想学习更多内容,我建议读 一些下面的文章:

分享到:
评论

相关推荐

    Android应用程序内存泄漏的分析.pdf

    标题中提到的是关于“Android应用程序内存泄漏的分析”,这意味着文档的核心内容将集中在分析Android平台下应用程序可能遇到的内存泄漏问题。内存泄漏是Android开发中非常常见且棘手的问题,它发生在一个对象不再被...

    Android应用程序开发

    ### Android应用程序开发知识点详解 #### 一、Android概述 Android是一种基于Linux内核的开源移动设备操作系统,由Google公司和开放手机联盟领导及开发。它主要用于触摸操作的手持设备上,如智能手机和平板电脑等...

    Android应用程序内存泄漏的分析[整理].pdf

    【Android应用程序内存泄漏的分析】 在Android应用开发中,内存泄漏是一个重要的问题,因为它会导致应用程序性能下降,甚至可能引发应用崩溃。尽管Java的垃圾回收机制(GC)在一定程度上减轻了程序员对内存管理的...

    纪喜才:Android应用程序内存管理优化.pptx

    本文将深入探讨Android应用程序内存管理优化的相关知识点。 首先,我们理解内存优化的重要性。Android系统为每个应用程序分配了一定量的内存资源,如果应用过度消耗内存,可能导致Out of Memory (OOM)错误,使应用...

    Android应用程序中的内存泄漏与规避方法

    造成Android应用程序内存泄漏的原因 ##### 1.1 引用未释放造成的内存泄漏 - **注册未取消**:在Android中,如果在活动或服务结束前未取消注册监听器、广播接收者等,即使活动或服务已经结束,但由于外部应用或...

    Android获取当前应用分配的最大内存和目前使用内存的方法

    在Android里,程序内存被分为2部分:native和dalvik,dalvik就是我们普通的Java使用内存,分析堆栈的时候使用的内存。我们创建的对象是在这里面分配的,对于内存的限制是 native+dalvik 不能超过最大限制. Android ...

    基于静态分析方法的Android应用内存泄漏检测模型.pdf

    基于静态分析方法的Android应用内存泄漏检测模型 Android 应用程序的内存泄漏问题较为常见,主要是由于部分开发人员对 Android 内存管理机制理解模糊所致。为了解决内存泄漏的检测问题,首先需要分析 Android 系统...

    88个经典Android应用程序打包下载(源代码).zip

    这个压缩包"88个经典Android应用程序打包下载(源代码).zip"包含了88款Android应用的源代码,为开发者提供了宝贵的参考资料。这些应用可能涵盖各种类型,如社交、游戏、工具、音乐、视频等,通过研究它们,开发者...

    Android应用程序开发宝典-基于TE&OK6410;.pdf

    此文档不仅覆盖了基本的Android应用程序开发流程,而且还提供了具体的案例分析和技术指导,使读者能够快速理解和应用这些知识。 #### 二、Android系统应用环境搭建 **2-1 UBUNTU10.10上编译ANDROID源码** - **2-1...

    Android应用程序架构.rar

    本文将深入探讨Android应用程序架构的关键组件、设计模式以及最佳实践,基于提供的压缩文件"Android应用程序架构.rar"中的文档内容进行详细阐述。 首先,Android应用程序由多个组件构成,主要包括Activity、Service...

    Android应用程序“计算器”

    【Android应用程序“计算器”】 Android应用程序“计算器”是基于谷歌Android操作系统开发的一款实用工具,它为用户提供基础到高级的计算功能,以便在移动设备上进行数学运算。Android平台以其开放性和丰富的开发...

    Android应用程序开发(第二版)代码

    《Android应用程序开发(第二版)代码》是一个针对Android平台应用开发的资源集合,主要涵盖了在Android Studio环境下构建、设计和优化应用程序的各种技术。这个压缩包包含的文件是开发者学习和实践Android编程的...

    AndroidStudio实战快速高效地构建Android应用 AndroidStudio 高清完整带目录书签 PDF AndroidStudio实战

    Android Studio作为Google官方推荐的Android应用程序开发集成开发环境(IDE),其功能强大且不断更新,是每一个Android开发者必备的工具。 本书涵盖了从Android Studio的基础操作到高级特性的全面内容,包括但不...

    88个经典Android应用程序打包下载

    这个压缩包包含了88个经典Android应用程序的源代码,是学习和研究Android开发不可多得的资源。 首先,我们可以从这些源码中学习到基础的Android组件使用,如Activity、Service、BroadcastReceiver和ContentProvider...

    《Android应用程序开发与典型案例》完整版PDF

    《Android应用程序开发与典型案例》是一本深入探讨Android应用开发的专业书籍,它涵盖了从基础到高级的各类主题,旨在帮助开发者全面掌握Android平台上的应用构建技巧。这本书提供了丰富的案例,通过实例解析来阐述...

    Android系统结构和SDK使用;Android SDK的开发环境;Android应用程序的概述和框架;Android应用程序示例;Android应用程序的内容;Android的UI系统实现;视图组(ViewGroup)和布局(Layout)的使用

    Android应用程序由多个组件构成,包括Activity、Service、Broadcast Receiver和Content Provider等。这些组件共同协作来完成特定的任务。 **5.2 应用程序包含的各个文件** 应用程序中的每个组件都需要对应的XML...

    HelloWorld之Android应用程序详细结构介绍

    【Android应用程序详细结构介绍】 Android应用程序的开发通常在Eclipse集成开发环境中进行,它提供了便捷的工具来创建和管理Android项目。"HelloWorld"作为入门级的程序,可以帮助初学者理解Android应用程序的基本...

    Android应用程序如何避免内存泄漏

    在Android应用程序开发中,内存泄漏是一个严重的问题,它可能导致应用性能下降、系统资源浪费甚至应用程序崩溃。虽然Java的垃圾收集器(GC)自动处理大部分内存管理,但在Android中,由于其特殊的生命周期和对Context...

Global site tag (gtag.js) - Google Analytics