转载请标明出处:http://blog.csdn.net/xx326664162/article/details/49949825 文章出自:薛瑄的博客
你也可以查看我的其他同类文章,也会让你有一定的收货!
MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。
当然MAT也有独立的不依赖Eclipse的版本,只不过这个版本在调试Android内存的时候,需要将DDMS生成的文件进行转换,才可以在独立版本的MAT上打开。不过Android SDK中已经提供了这个Tools,所以使用起来也是很方便的。
这里是MAT的下载地址:https://eclipse.org/mat/downloads.php,下载时会提供三种选择的方式:
Update Site 这种方式后面会有一个网址:比如http://download.eclipse.org/mat/1.4/update-site/ ,安装过Eclipse插件的同学应该知道,只要把这段网址复制到对应的Eclipse的Install New Software那里,就可以进行在线下载了。
Archived Update Site 这种方式安装的位置和上一种差不多,只不过第一种是在线下载,这一种是使用离线包进行更新,这种方式劣势是当这个插件更新后,需要重新下载离线包,而第一种方式则可以在线下载更新。
下载安装好之后,就可以使用MAT进行实际的操作了。
要看懂MAT的列表信息,Shallow heap、Retained Heap、GC Root 这几个概念一定要弄懂。
1、Shallow heap
Shallow size就是对象本身占用内存的大小,不包含其引用的对象。
2、Retained Heap
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来选择这个组。
为了计算Retained Memory,MAT引入了Dominator Tree。
举例:
对象A引用B和C,B和C又都引用到D(一个菱形)。
计算Retained Memory
在这里例子中,树根是A,而B,C,D是他的三个儿子。B,C,D不再有相互关系。
我觉得是为了加快计算的速度,MAT将对象引用图转换成对象引用树。把引用图变成引用树,计算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。这是个真正的引用图的概念,
为了更好地理解Retained Heap,下面引用一个例子来说明:
把内存中的对象看成下图中的节点,并且对象和对象之间互相引用。这里有一个特殊的节点GC Roots,这就是reference chain(引用链)的起点:
从obj1入手,上图中蓝色节点代表仅仅只有通过obj1才能直接或间接访问的对象。因为可以通过GC Roots访问,所以上图的obj3不是蓝色节点;而在下图却是蓝色,因为它已经被包含在retained集合内。
3、GC Root
名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性(那么JVM就是GC Roots),所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。
通常GC Roots是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。
这里介绍的不是MAT这个工具的主界面,而是导入一个文件之后,显示OverView的界面。
一、打开经过转换的hprof文件:
如果选择了第一个,则会生成一个报告。这个无大碍。
二、 选择OverView界面:
我们需要关注的是下面Actions区域,介绍4种分析方法:
Histogram:列出内存中的对象,对象的个数以及大小
Dominator Tree:列出最大的对象以及其依赖存活的Object (大小是以Retained Heap为标准排序的)
Top Consumers : 通过图形列出最大的object
Duplicate Class:通过MAT自动分析泄漏的原因
一般Histogram和 Dominator Tree是最常用的。
三、打开default_report窗口。
该窗口列出了,可能有问题的代码片段。点击Details可以查看相关的详情。
在Shortest Paths To the Accumulation Point的列表中,我们可以追溯到问题代码的类树的结构,并找到自己代码中的类。
在列表中,有两列Shallow Heap和Retained Heap。Shallow Heap指的是所有的实例的内存总和。Retained Heap指的是所有类实例被分配的内存总和,里面包括它们所有引用的对象。
在Accumulated Objects列表中,我们可以看见创建的大量的对象。
在Accumulated Objects by Class列表中,我们能看见创建大量对象相关的类。
1、Thread OvewView
Thread OvewView可以查看这个应用的Thread信息:
2、Group
在Histogram和Domiantor Tree界面,可以选择将结果用另一种Group的方式显示(默认是Group by Object),切换到Group by package,可以更好地查看具体是哪个包里的类占用内存大,也很容易定位到自己的应用程序。
3、Path to GC Root
在Histogram或者Domiantor Tree的某一个条目上,右键可以查看其GC Root Path:
点击Path To GC Roots –> with all references
这里也要说明一下Java的引用规则:
从最强到最弱,不同的引用(可到达性)级别反映了对象的生命周期。
Strong Ref(强引用):通常我们编写的代码都是Strong Ref,于此对应的是强可达性,只有去掉强可达,对象才被回收。
Soft Ref(软引用):对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。一般可用来实现缓存,通过java.lang.ref.SoftReference类实现。
Weak Ref(弱引用):比Soft Ref更弱,当发现不存在Strong Ref时,立刻回收对象而不必等到内存吃紧的时候。通过java.lang.ref.WeakReference和java.util.WeakHashMap类实现。
转载:http://www.jianshu.com/p/d8e247b1e7b2#
http://blog.csdn.net/p106786860/article/details/9268613
关注我的公众号,轻松了解和学习更多技术