网站制作网页制作,成都网站空间,哪里有免费网站空间申请,wordpress文章分类列表android 如何分析应用的内存#xff08;十七#xff09;——使用MAT查看Android堆
前一篇文章#xff0c;介绍了使用Android profiler中的memory profiler来查看Android的堆情况。 如Android 堆中有哪些对象#xff0c;这些对象的引用情况是什么样子的。
可是我们依然面临…android 如何分析应用的内存十七——使用MAT查看Android堆
前一篇文章介绍了使用Android profiler中的memory profiler来查看Android的堆情况。 如Android 堆中有哪些对象这些对象的引用情况是什么样子的。
可是我们依然面临一个比较严峻的挑战不管是app开发者还是内存分析者而言堆中的对象非常之多不仅有Android 原生的类还有第三方库使用的类。这些类在使用过程中也可能因为有较大的shallow size 或者retained size而混淆内存的分析。
为了解决这样的问题我们更希望通过不同时间点的堆进行差分比较。即在时刻t1生成的堆heap1和t2时刻生成的堆heap2进行相互比较。
为此我们将介绍java开发中重要的内存分析工具MAT。
MAT使用前的准备
在上一篇文章中我们使用AS捕获了堆现在我们需要将其导出用在MAT工具上。如下图
接下来将Android保存的heap dump进行格式转换以满足MAT的需求。转换格式的工具在Android SDK中。如下:
/Users/biaowan/Library/Android/sdk/platform-tools/hprof-conv ./mat/memory-test_malloc_int\[\].hprof mat_test1.hprofMAT的使用
打开MAT之后进入菜单栏-File-Open File。然后选择刚才转换之后的mat_test.hprof文件。如下图
可见主界面显示一个overview的界面该界面用英文详细表述了具体细节不在赘述。下面解释上图的八个标记。 标记1:打开overview 界面。即上面的主界面。 标记2:打开当前堆中的对象分布情况默认按照类名进行排序。右键可以进行相应操作各个操作什么意思已经标明。如下图 标记3:显示本heap中的所有dominator tree(注意dominator tree已经在上一篇文章中介绍android 如何分析应用的内存十六——使用AS查看Android堆:http://t.csdn.cn/GTWpR). 而各个对象应该怎么查看其对应的dominator tree。见标记2对应的右键说明。 标记4:Open Object Qurey Language,类似于使用SQL语句进行查询。因为MAT提供的菜单功能已经完全够Android使用因此本文不再介绍 标记5:展示线程的名字堆栈本地变量等。但是Android 没有提供这个功能因此无法使用 标记6:打印各种报告如下图标记 标记7:即为标记2中右键支持的各种操作详见标记2 标记8:搜索按钮可以按照地址进行搜索
为了能够详细说明如何操作MAT下文将会以各种问题作为模板详细介绍操作过程
问题1:如何查看某个类有哪些对象
点击标记1打开所有类的列表。在第一行键入需要查找的类或者按照不同的大小进行排序和过滤选中类然后点击右键选择List Objects.然后按照需求列出各个对象
问题2:如何查看某个对象到GC root的引用链
选中某个对象右键选中Paths to GC root再次选中exclude all xxx references
可见整个引用链清晰明了不在绘图说明
问题3:如何查看对象的Dominator tree(支配树)
选中对象右键选择Java Basics再次选中Open in Dominator tree在弹出的框中选择finish。默认以对象排序
从图中可以看到TaskRunable对象直接支配两个对象一个int数组一个弱引用
问题4:如何查看一个对象的直接支配者
选中对象然后右键选择immediate dominator在弹出框中选择finish
可以看到我们选中的TaskRunable对象的直接支配者是一个Task对象
问题5:如何查看类加载器是否重复加载同一个类
点击标记1打开overview界面滚动界面到最底下选择Duplicate classes
问题6:如何查看堆中最占内存的部分
点击标记1打开overview界面滚动至最底下选择Top cosumer
从图中可以看到分别按照对象类类加载器包名列出了最占内存的部分
问题7:如何查看堆的报告
点击标记6.选择Heap dump overview在对报告中点击table of content 查看内容表该字段在报告的底部
从中也可以直接查看最占内存的对象
问题8:如何进行泄露检查
点击标记6选择Leak Suspect
从图中可以看到有三个怀疑的对象往下滚动可以看到三个怀疑对象的详细细节如下
图中简要说明了Task类有2100个实例占了29.51%的内容。点击details它会显示相应的引用链路径。可清晰看到GC root的整个引用链。
多个Heap进行差分分析查找内存问题
为了一步步演练如何使用多个heap进行差分分析我们选择上一篇文章方案2中的例子android 如何分析应用的内存十六——使用AS查看Android堆http://t.csdn.cn/JYGFC。然后在同一个进程的两个不同时刻分别选取不同的heap,分别叫as_heap1.hprof和as_heap2.hprof.
场景1MAT 自动分析两个堆之间的内存泄露 按照上文提及的hprof-conv工具将as_heap1.hprof,as_heap2.hprof分别转换为mat_heap1.hprof,mat_heap2.hprof。然后用mat工具将其打开。 打开第二个heap的overvie操作栏即标记1。滚动到最底部 选择Leak suspects by Snapshot comparision. 在弹出的框中选择mat_heap1.hprof。然后点击finish。让mat_heap2.hprof与mat_heap1.hprof做差分分析然后给出一个报告如下(需要等待一段时间)
从图中可以看到怀疑com.example.test_malloc.Task对象泄露它有4900个对象占整个堆的49.26%。点击details可以看到这个引用链如下图
从图中可以看到Task被DeviceManager的listener所持有导致GC无法回收。所以找到了内存泄露点。
场景2无法自动分析时手动分析
当两个heap堆间隔时间较短泄露的对象占据整个堆的空间较小此时mat无法进行自动分析。此时我们可以手动分析。
接下来我们用时间间隔较小的两个堆分别叫mat_heap3.hprof和mat_heap4.hprof 注意mat_heap3.hprof和mat_heap4.hprof是用AS 重新抓取的时间间隔较近的两个堆 用mat打开mat_heap3.hprof,和mat_heap4.hprof 按照问题6输出消耗内存最大的部分。下面是mat_heap3.hprof的报告。
从中我们看到占据内存最大的首要对象是int数组。接下来我们手动分析两个堆中的int数组之间的差距——即mat_heap4.hprof比mat_heap3.hprof多了哪几个int数组 点击mat_heap3.hprof的统计信息即标记2.然后选中int[]。右键列出所有的对象。如下图 点击操作历史记录栏右键list_objects… 然后点击add to compare basket。如下图 因为我们需要比较两个heap堆的int[]情况因此选中mat_heap4.hprof之后按照步骤34做同样操作。将会在compare basket窗口两个需要比较的对象。然后点击感叹号开始比较即可。如下
对测试结果进行简单排序shallow_heap #1 升序排列。即可展示heap3中没有而heap4中具有的对象。这也是从抓取heap3时刻到抓取heap4时刻之间堆中多出来的int数组对象。为前排的10个对象。
按照前文的问题2即可查看其引用链从而分析被谁持有为何没有被释放掉。
在第2步中输出的top comsumer除了int数组以外还有其他的对象因此按照步骤345即可进行两个堆的比较。我们已经以int[]为例子做了详细说明就不再一一比较。
除了使用top comsumer辅助定位需要比较的对象以外还可以对任何怀疑的对象进行比较。步骤完全相同。
至此MAT的使用介绍完毕。
MAT弥补了AS在内存分析上的如下不足
无法自定义Retained Set(这对于大型应用很有用)无法进行地址查找无法进行堆之间的比较无法按照需要进行排序无法按照需要进行过滤等
虽然MAT已经足够强大但是依然还有一个内存问题悬而未决——怎么才能知道这些内存泄露是由哪一个线程触发它们又有怎样的调用栈
在多线程编程中对象的泄露即可能是对象之间的引用不合理也可能是线程之间的逻辑不合理如生产线程和消费线程不够合理等等。MAT无法解决Android线程所带来的内存泄露。
接下里请期待如何用工具找到这种多线程带来的内存泄露。