Android内存分析和调优(中)

转载 2013年12月05日 16:29:57

前文中讨论了如果使用adb shell procrank, dumpsys meminfo和showmaps分析进程的内存占用情况。

本文将继续细化,具体分析导致内存过大的dalvik heap。

Dalvik heap分析和优化

Dalkvik heap是最常见的android应用内存优化的对象。

通过上文的分析,我们可以通过adb shell的命令,知道用了多少dalvik heap。在ADT的eclipse的DDMS视图,可以更细致的查看这些内存用到什么地方。
参考DDMS使用说明(搜索viewing heap),我们可以首先在devices view中选中一个进程,然后enable "update heap“(不带红箭头的半杯水图标),之后在heap view中点击”Cause GC"。这样子除了Heap Size, Allocated, Freed,还可以看到data object,class object,和n-byte array分别占用的内存大小。

不过真心说,这个还是太粗糙了,没法精确到具体的类。此时大名鼎鼎的MAT就派上用场了。

MAT是对java内存镜像进行分析的工具。所以首先需要导出进程的内存镜像,可以在DDMS上的device view点击Dump HPROF file(带红箭头的半杯水图标),生成hprof文件。因为android的文件格式跟通用的java的hprof格式不一样,还需要通过hprof-conv命令来转换。然后就可以用MAT来打开。

看起来挺麻烦的。事实上,现在MAT的eclipse插件可以把上面的工具一键完成。只需要点击Dump HPROF file图标,然后MAT插件就会自动转换格式,并且在eclipse中打开分析结果。eclipse中还专门有个Memory Analysis视图,可以更详细的查看MAT的分析结果。

MAT可以根据内存镜像,以可视化的方式告诉我们哪个类,哪个对象分配了多少内存。但如果只是这样,用处就没那么大了。因为不像c++的对象本身可以存放大量内存,java的对象成员都是些引用。真正的内存都在堆上,看起来是一堆原生的byte[], char[], int[]。所以我们如果只看对象本身的内存,那么数量都很小。我们称之位shallow heap。

于是MAT提出了Retained Heap的概念,它表示如果一个对象被释放掉,那会因为该对象的释放而减少引用进而被释放的所有的对象(包括被递归释放的)所占用的heap大小。于是,如果一个对象的某个成员new了一大块int数组,那这个int数组也可以计算到这个对象中。相对于shallow heap,Retained heap可以更精确的反映一个对象实际占用的大小(因为如果该对象释放,retained heap都可以被释放)。这里要说一下的是,Retained Heap并不总是那么有效。例如我在A里new了一块内存,赋值给A的一个成员变量。此时我让B也指向这块内存。此时,因为A和B都引用到这块内存,所以A释放时,该内存不会被释放。所以这块内存不会被计算到A或者B的Retained Heap中。为了纠正这点,MAT中的Leading Object(例如A或者B)不一定只是一个对象,也可以是多个对象。此时,(A, B)这个组合的Retained Set就包含那块大内存了。对应到MAT的UI中,在Histogram中,可以选择Group By class, superclass or package来选择这个组。(又开始Histogram中不显示Retained heap,需要点击那个计算器的按钮才会计算出来)。这里最小的粒度是类级别的。

为了计算Retained Memory,MAT引入了Dominator Tree。加入对象A引用B和C,B和C又都引用到D(一个菱形)。此时要计算Retained Memory,A的包括A本身和B,C,D。B和C因为共同引用D,所以他俩的Retained Memory都只是他们本身。D当然也只是自己。我觉得是为了加快计算的速度,MAT改变了对象引用图,而转换成一个对象引用树。在这里例子中,树根是A,而B,C,D是他的三个儿子。B,C,D不再有相互关系。把引用图变成引用树,计算Retained Heap就会非常方便,显示也非常方便。对应到MAT UI上,在dominator tree这个view中,显示了每个对象的shallow heap和retained heap。然后可以以该节点位树根,一步步的细化看看retained heap到底是用在什么地方了。要说一下的是,这种从图到树的转换确实方便了内存分析,但有时候会让人有些疑惑。本来对象B是对象A的一个成员,但因为B还被C引用,所以B在树中并不在A下面,而很可能是平级。

为了纠正这点,MAT中点击右键,可以List objects中选择with outgoing references和with incoming references。这是个真正的引用图的概念,表示该对象的出节点(被该对象引用的对象)和入节点(引用到该对象的对象)。

另外一个类似的功能是右键菜单的Path to GC RootsGC roots是可能导致GC的节点。这个Path则是从这些GC root节点中的某个到当前对象的最短引用路径。对这个如何计算不是很确定,我想应该是根据引用树而不是dominator tree。后面会看到这个功能在非常的有用。

说完工具,下面是具体的减少内存大小。一般要解决两个问题:内存泄露和释放暂时不需要的内存。

Java内存泄露归根结底都是一个原因导致的,应该被释放的对象被生命期更长的对象引用,所以没法被GC。这个生命期更长的对象很常见的是static对象,会持续整个进程。在个人实际工作中,我会先用adb shell dumpsys meminfo查看dalvik heap会不会持续增长。如果是,我会在在dominator Tree中按照Retained Memory排序,找出比较大的(经常是Bitmap),然后用Path to GC Roots看看其引用情况。在这个Path中,一般会发现我们app自己包的类,可以分析这个类是不是还是需要的。如果不需要,那说明可能存在内存泄露。此时,在对这个自己包的类查看incoming references。看看到底是哪些引用导致它没有释放。用这种方法,会比较快的发现问题。MAT自己也提供了智能的内存分析工具,我没有用,不好评论。

一个制造内存泄露的很有效的办法是不断的切换横屏和竖屏。现实中很多内存泄露都是因为static的对象指向了Activity对象(作为context传),而切换横屏和竖屏会导致Activity重新生成。所以如果有问题,内存很快就会变大。从编码上讲,avoid-memory-leak这篇文章教育我们,在需要context的地方,尽量使用getApplicationContext,而不是Activity本身。

另外一个可以减少内存的方法是删除临时不用的内存。编码中可能是为了内存cache以提高性能,可能只是偷懒,之前场景使用的内存并没有被释放掉。这样子下次再回到这个场景,会快一点;但会可能会占用不少内存。我觉得在android这类内存受限的系统上,还是应该谨慎使用控件换时间的策略。如果想删除临时不用的内存,也可以使用mat像监测内存泄露一样,看看哪些比较大的内存临时不用却仍然被引用,然后删除对其引用。

关于mat的一个小技巧是mat经常发现比较大的内存泄露是图片,此时如果知道图片是什么内容就很容易定位到何时导致的内存泄露。这个帖子回答了这个问题。

关于dalvik mat最后再推荐自己看的一个android memory manage video(slides , contentcontent2)。里面对MAT和内存泄露都有介绍。这个blog也是对二者都有介绍,很好。关于MAT更好的文档集合在这里,MAT作者写的。

高效地分析Android内存--MAT工具解析

欢迎Follow我的GitHub, 关注我的CSDN. MAT(Memory Analyzer Tool), 是著名的Android内存分析工具, 虽然LeakCanary更加便捷, 但是MAT可以清...
  • u012515223
  • u012515223
  • 2016年02月01日 17:23
  • 4115

Android最佳性能实践(二)——分析内存的使用情况

由于Android是为移动设备开发的操作系统,我们在开发应用程序的时候应当始终把内存问题充分考虑在内。虽然Android系统拥有垃圾自动回收机制,但这并不意味着我们就可以完全忽略何时去分配或释放内存。...
  • sinyu890807
  • sinyu890807
  • 2015年02月12日 09:09
  • 74863

Android 性能优化之使用MAT分析内存泄露问题

我们平常在开发Android应用程序的时候,稍有不慎就有可能产生OOM,虽然JAVA有垃圾回收机,但也不能杜绝内存泄露,内存溢出等问题,随着科技的进步,移动设备的内存也越来越大了,但由于Android...
  • xiaanming
  • xiaanming
  • 2015年01月09日 08:50
  • 33203

Android studio内存泄露分析工具

使用 Android Studio 检测内存泄漏与解决内存泄漏问题      本文在腾讯技术推文上 修改 发布。     http://wetest.qq.com/lab/view/63.ht...
  • gao878280390
  • gao878280390
  • 2017年02月20日 10:12
  • 982

Android Studio MAT内存分析初探

做开发有一些年头的想必都会碰到程序性能方面的问题,性能优化有很多种,但是首先我们得定位是哪一块的问题;Android Studio已经为我们提供了性能分析工具MAT。...
  • mackkill
  • mackkill
  • 2017年04月01日 18:04
  • 1325

在Eclipse中使用MAT分析Android程序内存使用状况

对于Android这种手持设备来说,通常不会带有太大的内存,而且一般用户都是长时间不重启手机,所以编写程序的时候必须要非常小心的使用内存,尽量避免有内存泄露的问题出现。通常分析程序中潜在内存泄露的问题...
  • Roland_Sun
  • Roland_Sun
  • 2015年05月27日 17:46
  • 1396

android内存分析工具- MAT的初识(1)

DDMS(Dalvik Debug Monitor Server)和MAT(Memory Analyzer Tool)这两个工具可以很好地帮助我们分析优化内存。MAT是一个Eclipse插件,同时也有...
  • dfskhgalshgkajghljgh
  • dfskhgalshgkajghljgh
  • 2016年01月13日 23:21
  • 1204

Android内存泄露分析(MemoryAnalyzer工具)

前提条件: 1,电脑安装了java 运行环境   2,手机端开启了 USB 调试开关  3,获取 root 权限 基本步骤: 1,使用eclipse 自带的 DDMS 工具分析各线程的内存使...
  • pugongying1988
  • pugongying1988
  • 2013年06月18日 17:53
  • 36563

Android 性能优化&内存篇

Android内存分析方向: Java 内存分析 Java中的内存泄露主要特征:可达,无用无用指的是创建了但是不再使用之后没有释放能重用但是却创建了新的对象进行处理 Native 内存分...
  • namesuper
  • namesuper
  • 2017年01月03日 09:41
  • 411

使用新版Android Studio检测内存泄露和性能

内存泄露,是Android开发者最头疼的事。可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴。怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的An...
  • yangxi_001
  • yangxi_001
  • 2016年07月08日 14:57
  • 14464
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android内存分析和调优(中)
举报原因:
原因补充:

(最多只允许输入30个字)