Android进阶之路Android开发经验谈Android开发

Android内存优化工具:MAT

2019-08-03  本文已影响7人  小村医

一、获取HPROF文件

HPROF文件是MAT能识别的文件,HPROF文件存储的是特定时间点,java进程的内存快照。有不同的格式来存储这些数据,总的来说包含了快照被触发时java对象和类在heap中的情况。由于快照只是一瞬间的事情,所以heap dump中无法包含一个对象在何时、何地(哪个方法中)被分配这样的信息。
这个文件可以使用Memory Profiler导出(详见Android内存优化工具:Memory Profiler)

二、MAT主要界面介绍

得到对应的文件后,要使用Android SDK自带的的工具(hprof-conv 位置在sdk/platform-tools/hprof-conv)进行转换

hprof-conv heap-original.hprof heap-converted.hprof

用MAT打开转换过的HPROF文件是,就有一个弹窗询问展示哪一种报告:


image.png

选择内存泄漏报告后,打开看的的第一个界面如下图所示:


内存泄漏报告.png

OverView界面:

OverView界面.png

我们需要关注的是下面的Actions区域:

一般Histogram、Dominator Tree、Thread Overview是最常用的

三、MAT中一些概念介绍

Shallow heap

Shallow size就是对象本身占用内存的大小,不包含其引用的对象。

Retained Heap

Retained Heap的概念,它表示如果一个对象被释放掉,那会因为该对象的释放而减少引用进而被释放的所有的对象(包括被递归释放的)所占用的heap大小。于是,如果一个对象的某个成员new了一大块int数组,那这个int数组也可以计算到这个对象中。相对于shallow heap,Retained heap可以更精确的反映一个对象实际占用的大小

Retained Heap并不总是那么有效。例如我在A里new了一块内存,赋值给A的一个成员变量。此时我让B也指向这块内存。此时,因为A和B都引用到这块内存,所以A释放时,该内存不会被释放。所以这块内存不会被计算到A或者B的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到底是用在什么地方了。

为了纠正这点,MAT中点击右键,可以List objects中选择with outgoing references和with incoming references。这是个真正的引用图的概念,

GC Root

GC发现通过任何reference chain(引用链)无法访问某个对象的时候,该对象即被回收。名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性(那么JVM就是GC Roots),所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。通常GC Roots是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。

四、发现内存泄漏对象

在Histogram或者Domiantor Tree的某一个条目上,右键可以查看其GC Root Path:


GC Root Path.png

点击Path To GC Roots —> exclude all phantom/week/soft etc. references


GC Roots.png
上一篇 下一篇

猜你喜欢

热点阅读