热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(转todo阅读)Android官方博客Android应用程序的内存分析(翻译)

作者:TimBrayDalvik虚拟机支持垃圾收集,但是这不意味着你可以不用关心内存管理。你应该格外注意移动设备的内存使用,在上面内存空间是受到限制的。在这篇文章里面,我们

 

作者:Tim
Bray

bubuko.com,布布扣
src="https://img.php1.cn/3cd4a/1eebe/cd5/70be2ca197098d98.webp"
border="0">

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

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

>必要的工具:class="Apple-converted-space"> 

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


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

分析heap
dump,你可以使用一些标准的工具比如jhatclass="Apple-converted-space"> 或者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 appclass="Apple-converted-space"> 。它是一个photo
gallery程序,用来演示一些新的Honeycomb API的使用。(下载和编译这些代码,请看这些命令class="Apple-converted-space"> 。)我们会有意地加入一个内存泄露在程序里边,然后来演示如何调试它。

bubuko.com,布布扣
src="https://img.php1.cn/3cd4a/1eebe/cd5/0a0ce631ec450943.webp"
border="0">

 

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




  1. > class="keyword" >private class="keyword" >static >
    HashMap sBitmapCache =
    >new >
    HashMap(); 

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




  1. > class="keyword" >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-inclass="Apple-converted-space"> 的一部分,独立的程序版本也可以在Android
SDK的根目录下的tools/下面找到。关于DDMS更多的信息,请参考使用DDMSclass="Apple-converted-space"> 

 

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



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

  • or from the
    command line: run ddms class="Apple-converted-space"> (or  >./ddms class="Apple-converted-space"> on Mac/Linux) in the  >tools/ class="Apple-converted-space"> directory

bubuko.com,布布扣
src="https://img.php1.cn/3cd4a/189d8/b64/5b34b53b79a39fdd.jpeg"
border="0">

 


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

 

bubuko.com,布布扣
src="https://img.php1.cn/3cd4a/9b0d/ae9/2d998ad7838fbf16.jpeg"
border="0">

 


们可以看到现在的值(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(所有类实例被分配的内存总和,里面也包括他们所有引用的对象)。

bubuko.com,布布扣
src="https://img.php1.cn/3cd4a/1eebe/cd5/bdd1ca32a69bc8b2.webp"
border="0">

 


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

 

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

 

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

bubuko.com,布布扣
src="https://img.php1.cn/3cd4a/1eebe/cd5/1e3db12dd78db092.webp"
border="0">

 

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

 

>使用MAT比较heap
dumps

 

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



  1. 第一个HPROF
    文件(using File
    > Open Heap Dump
    class="Apple-converted-space"> ).

  2. 打开 Histogram
    view.

  3. 在Navigation
    History view里 (如果看不到就从Window
    > Navigation History找
    class="Apple-converted-space"> ), 右击histogram class="Apple-converted-space"> 然后选择Add
    to Compare Basket
     .

  4. 打开第二个HPROF
    文件然后重做步骤2和3.

  5. 切换到Compare Basket
    view, 然后点击Compare
    the Results
    class="Apple-converted-space"> (视图右上角的红色"!"图标)。

>总结


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



  • Memory Analyzer
    News : Eclipse MAT
    project的官方博客。

  • Markus Kohler的Java
    Performance blog有很多有用的文章, 包括 class="Apple-converted-space"> Analysing
    the Memory Usage of Android Applications with the Eclipse Memory
    Analyzer and 10
    Useful Tips for the Eclipse Memory Analyzer .

 

(转 todo阅读)Android 官方博客 - Android应用程序的内存分析(翻译),布布扣,bubuko.com


推荐阅读
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
author-avatar
手机用户2602930391
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有