内存泄漏和内存溢出是安卓开发中经常碰到的问题,如何能够快速有效的发现并追踪内存泄漏或者内存溢出的源头,是每个开发者都需要掌握的技巧,今天我给大家带来常见的内存分析工具使用方法,希望对大家今后的开发带来帮助。
使用Eclipse分析应用内存使用情况具体步骤如下:
1.启动eclipse后,切换到DDMS透视图,并通过Window-ShowView打开Devices视图、Heap视图
2.连接手机或者模拟器后,在DDMS的Devices视图中将会显示手机设备或模拟器的序列号,以及设备中正在运行的部分进程信息
3.点击选中想要监测的进程,然后再点击下Update Heap让其自动找到我们运行中应用的进程
4.点击Heap视图中的“Cause GC”按钮,请求一次GC操作(PS:当内存使用信息第一次显示以后,无须再不断的点击“Cause GC”,Heap视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化)
5.点击Cause GC之后就可以看到我们应用的内存情况如下图:
6.具体使用过程中,我们要关注 Heap视图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类的对象。在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java数据对象的内存总量,如果大家想要看“Total Size”是分配的具体信息可以点击“data object这一行来查看详细信息,如下图:
在使用中 “Total Size”这个值的大小决定了是否会有内存泄漏。我们可以通过不断的操作当前应用,同时观察data object的Total Size值的变化情况;正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;反之如果代码中存在没有释放对象引用的情况,则data object的Total Size值在每次GC后不会有明显的回落,随着操作次数的增多Total Size的值会越来越大,正常情况下,一个虚拟机的进程的内存在64M, 如果内存泄漏会发现 Heap Size 在不断的逼近 64M, 一旦达到这个值时,就会出现内存泄漏退出应用等情况。
Total Size的值越来越大时,我们按下“Dump HPROF File”按钮,这个时候会提示设置hprof文件的保存路径。保存后,我们可以使用MAT工具来分析是哪些操作造成了内存泄漏。
Eclipse Memory Analyzer(MAT)是著名的跨平台集成开发环境 Eclipse Galileo 版本的 33 个组成项目中之一,它是一个功能丰富的JAVA 堆转储文件分析工具,可以帮助你发现内存漏洞和减少内存消耗。对于大型 JAVA 应用程序来说,再精细的测试也难以堵住所有的漏洞,即便我们在测试阶段进行了大量卓有成效的工作,很多问题还是会在生产环境下暴露出来,并且很难在测试环境中进行重现。JVM 能够记录下问题发生时系统的部分运行状态,并将其存储在堆转储 (Heap Dump) 文件中,从而为我们分析和诊断问题提供了重要的依据。
官方网站:http://www.eclipse.org/mat/
从官网中下载最新的MAT工具,打开后如下图:
废话不多说,MAT的使用步骤如下:
1.打开 MAT 工具,File–>Open Heap Dump… 选择你刚刚保存的 hprof 文件打开
此时,会弹出一个错误,如下图所示:
不要以为是 MAT 工具版本不对,其实是 android 的 hprof 文件在这里需要进行转换一下格式才可以使用 MAT 打开,使用AndrodiSDK/tools/hprof-conv转化hprof文件,
首先,要通过控制台进入到你的 android sdk tools 目录下
例如 hprof-conv input.hprof out.hprof
再使用MAT工具打开转换后的 hprof 文件,就能看到完整的内存使用分析报告了
2.如下所示是 MAT 分析内存使用的主界面:
点击上图中的 Reports –>Leak Suspects 则可以进一步看到更详细的内存泄漏疑点
在其中怀疑的地方,点击 Details 就可以看到具体的内存使用情况了。
从上图中我们可以看到内存聚集点是一个拥有大量对象的集合,这个对象集合中保存了大量 Person 对象的引用,就是它导致的内存泄露。
3.另外我们经常会使用Histogram查询
在某一项上右键打开菜单选择 list objects ->with incoming references 将列出该类的实例,也可以点击表头进行排序,在表的第一行可以输入正则表达式来匹配结果
4.在选中某一项上右键打开菜单选择 list objects ->with incoming refs 将列出该类的实例:
在新打开的Tab页面中展示了对象间的引用关系。
如果想查看某个实例没被释放的原因,可以右健 Path to GC Roots–>exclue all phantom/weak/soft etc. reference :这样变可以快速查看某个对象的 GC Root
5.有时候为查找内存泄漏,我们通常需要两个Dump结果作对比,这时我们可以打开 Navigator History面板,将两个表的 Histogram结果都添加到 Compare Basket中去 :
然后点击面板右上角的红色叹号,得到对比结果:
同时也可以改变对比条件:
现在开发者普遍使用AndroidStudio进行开发,关于内存使用的分析更加人性化,其内部也默认支持hprof文件的分析,下面带领大家一起学习一下:
(一) 使用AndroidStudio追踪内存使用状况,打开Android Monitor面板(PS:快捷键Alt+6),点击Memory选项卡
(二) 使用AndroidStudio分析hprof文件,具体步骤如下:
1. 在AndroidStudio菜单栏中开Android Device Monitor,如下图:
2.在Android Device Monitor界面中选在你要分析的应用程序的包名,同时点击Update Heap用来更新统计信息,然后点击Cause GC即可查看当前堆的使用情况,如下图
3.点击Dump HPROF file,将该应用当前的内存信息保存成hprof文件,存放到你所指定的路径,如下图
4.在File菜单栏中打开刚才保存的hprof文件(当然为了省事,你也可以直接将hprof文件拖入AndroidStudio中)
5.在打开的hprof文件中,我们可以很容的找到自己应用程序的包名,打开对应包就可以看到内存使用情况。
LeakCanary 是一个开源的在debug版本中检测内存泄漏的java库。
GitHub地址:https://github.com/square/leakcanary
(一)配置说明:
(二)使用案例:
创建一个RefWatcher实例,然后给它一个对象让它观察:
refWatcher.watch(schrodingerCat);
当检测出泄漏的时候,你会自动得到一个漂亮的泄漏线索:
- GC ROOT static Docker.container
- references Box.hiddenCat
- leaks Cat instance
然后只需几行代码,LeakCanary就能自动检测Activity的泄漏:
最终当出现内存不足时,你将看到如下通知界面:
也就是说,启用LeakCanary之后,可以帮助我们更加方便的发现和修复许多内存问题。