MAT 工具是基于 Eclipse 平台开发的, 本身是一个 Java 程序, 是一款很好的内存分析工具, 所以如果堆快照比较大的话, 则需要一台内存比较大的分析机器, 并给 MAT 本身加大初始内存, 这个可以修改安装目录中的 MemoryAnalyzer.ini 文件。
在MAT中,我们一般比较常用的几个小工具,如下图标识所示
柱状图中,主要看每个class对应的实例数、浅堆、深堆等。如下图所示
从这个图的展示效果看出,和“jmap -histo <pid> ”命令展示的效果很像。
而我们大部分情况下,我们关注重点,是深堆或浅堆的incoming和outgoing两项,那么这两项指的是什么呢?
1、对象的引入(incoming references)
通俗的来讲,就是哪些对象把当前对象引用了,那么那些对象对于当前对象来说就是一些引入对象。
2、对象的引出(outgoing references)
通俗的来讲,就是当前对象中引用了哪些对象,那么那些对象对于当前对象来说就是一些引出对象。
下面就使用例子进行说明,准备如下代码
那么这一段码的意图,可以翻译为下面的图所示
下面我们就来分析对象C的Incoming和outgoing
将代码使用main方法运行起来,然后使用MAT连接。
注意MAT不单单只打开 dump 日志,也可以打开正在运行的 JVM 进程, 跟 arthas 有点类似,效果是一样的,只是一个是动态的,一个是日志导出那个时刻的。
使用MAT连接正在运行的进程方式如下图所示
选中如图中标识的这个进程并双出打开
这个 outgoing references 和 incoming references 非常有用, 因为我们做 MAT 分析一般时对代码不了解, 排查内存泄漏也好, 排查问题也好, 垃圾回收中有一个很重要的概念, 可达性分析算法, 那么根据这个引入和引出, 我就可以知道这些对象的引用关系, 在 MAT 中我们就可以知道比如 A,B,C,D,E,F 之间的引用关系图, 便于做具体问题的分析。
1、概念
浅堆(shallow heap) 代表了对象本身的内存占用, 包括对象自身的内存占用, 以及“为了引用” 其他对象所占用的内存。
深堆(Retained heap) 是一个统计结果, 会循环计算引用的具体对象所占用的内存。 但是深堆和“对象大小” 有一点不同, 深堆指的是一个对象被垃圾回收后, 能够释放的内存大小, 这些被释放的对象集合, 叫做保留集(Retained Set)
2、浅堆大小的计算
我们知道,一个对象的大小是由三个部分组成,即对象头、实例数据、对齐填充。
而我们在实际使用中,一个对象会引用其它的对象或一些基本的成员变量。那么这个浅堆大小的计算公式如下
其中,各成员变量大小之和就是实例数据,如果存在继承的情况,需要包括父类成员的变量。
除了对象,我们还需要知道数组类型对象的浅堆该如计算。计算体公式如下
这里的类型变量大小*数组长度, 就是实例数据, 强调是变量不是对象本身
3、实例辨析
下面,给出一张图,我们来看一下,A、B、D这三个对象的深堆和浅堆是怎么得出来的
1、对于A对象而言,浅堆就是自身的大小,即大小为10;深堆的计算可就没有这么简单了,前面说过,对象的深堆是指如果对象被回收了,它所能释放出多少空间,那这么这个释放出来的空间就是深堆大小。从图中,可以看出从A出发,是有6个对象实例,而每个实例的大小是10,但是对象本身的大小是10,所以A的深堆就是70
2、对于B对象而言,按照A对象的计算方式,不能算出,它的浅堆大小是10,而深堆大小是30
3、对于D对象而言,如果D被回收了,它也只释放出的空间大小为10,即它自身的大小。所以它的浅堆和深堆都是10。因此,如果我们在使用MAT工具在分析时,看到浅堆和深堆的大小是一样的话,就可以断定,这个对象就没有引用其它对象了。
下面再看一个图
在这种情况下, 对象A的深堆大小将从之前的 70 减小到 40 个字节。如果对象A被垃圾回收了, 则将仅会影响C、 F 和 G 对象的引用,所以仅对象C、F和G 将被垃圾回收。另一方面, 由于H持有对B的引用,对象B、D和E将继续存在于内存中。即使 A 被垃圾回收,B、D和E也不会从内存中删除。
总结:我们可以看到在进行内存分析时,浅堆和深堆是两个非常重要的概念,尤其是深堆,影响着回收这个对象能够带来的垃圾回收的效果,所以在内存分析中,我们往往会去找那些深堆比较的大的对象, 尤其是那些浅堆比较小但深堆比较大的对象, 这些对象极有可能是问题对象。
内存泄露检测
在日常开发中,我们可能会遇到内存泄露问题而不自知,这种问题将会是致命的,如果不找出其中的根原,那么这么始终是一个定时炸弹。那么对于内存泄露这一类的问题,就可以使用MAT工具进行分析。
下面,准备一段简单的代码,如下
我们将这段代码使用main方法运行起来,并使用MAT进行连接
从上图中,可以看到,存在一个"hl-thread"的线程,它的深堆和浅堆的差距非常的巨大。持有99.53%的对象,数据被一个HashMap所持有。
那么这个就是一个泄露点,因为在代码中对线程做了标识 。所以我们在日常的开发中,如果有用到线程的,最好还是给线程取上名称,这样对排查问题有很大的帮助。
所以, 如果是对于特别明显的内存泄漏, 在这里能够帮助我们迅速定位, 但通常内存泄漏问题会比较隐蔽, 我们需要做更加复杂的分析。
支配树视图
从上图的层层分解得出。原来是“hl-thread”的深堆和浅堆比例很多(深堆比浅堆多很多,一般经验都是找那些浅堆比较小,同时深堆比较大的对象)
经过分析,内存泄露点就在于此。
线程视图
想要看具体的引用关系, 可以通过线程视图。 线程在运行中是可以作为 GC Roots 的。 我们可以通过线程视图展示了线程内对象的引用关系, 以及方法调用关系, 相对比 jstack 获取的栈 dump, 我们能够更加清晰地看到内存中具体的数据。
还有另外一段是陷入无限循环,这个是相互引用导致的(进行问题排查不用被这种情况给误导了,这样的情况一般不会有问题,可达性分析算法的解决了相互引用的问题) 。
柱状图视图
柱状图视图,可以看到除了对象的大小, 还有类的实例个数。 结合 MAT 提供的不同显示方式, 往往能够直接定位问题。 也可以通过正则过滤一些信息,我们在这里输入MAT,过滤猜测的、可能出现问题的类, 可以看到, 创建的这些自定义对象, 刚好100个对象实例,而在代码中指定就是100
下面我们看一下对象A的引入,即A被哪些对象引用了。
Path To GC Roots
使用这种方式, 即可在引用之间进行跳转, 方便的找到所需要的信息(这里从对象反推到了线程 hl-thread) ,也可以快速定位到有内存泄漏的问题代码。
高级功能QOL
MAT工具支持一种类似于 SQL 的查询语言 OQL(Object Query Language) ,这个查询语言VisualVM工具也支持,不过一般情况下不用VisualVM工具。使用方法如下图
查询A对象
当然了,QOL用还有更多的用法,可以参考网址 http://tech.novosoft-us.com/products/oql_book.htm
到此这篇hprof文件怎么分析 mat(hprof文件怎么分析)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/rfx/65886.html