本文首发于公众号:javaaduphp
尽管JVM提供了自动内存管理的机制,试图下降程序员的开发门槛,确实也实现了这一目标,在平常开发中,咱们通常都不须要关心对象的内存释放。JVM大部分都是使用trace算法来判断一个对象是否该被回收,那么JVM只能回收那些从gc roots不可达的对象。java
若是咱们在使用某些大的对象、集合对象或者一些三方包里的资源,忘记及时释放资源的话,仍是会形成JVM的内存泄漏或内存浪费的问题。所以,若是想成为更高阶的Java开发工程师,咱们须要了解常见的问题排查的办法和工具,这个系列的文章,准备介绍一个用来作JVM堆内存分析的工具——MAT(Memory Aanlysis Tool)。程序员
MAT的官网在:https://www.eclipse.org/mat/,能够看下它的介绍——MAT是一款高性能、具有丰富功能的Java堆内存分析工具,能够用来排查内存泄漏和内存浪费的问题。面试
MAT 支持两种安装方式,一种是"单机版“的,也就是说用户没必要安装 Eclipse IDE 环境,MAT 做为一个独立的 Eclipse RCP 应用运行;另外一种是”集成版“的,也就是说 MAT 也能够做为 Eclipse IDE 的一部分,和现有的开发平台集成。算法
这里咱们考虑独立安装,在观望的下载页面,选择mac os版本的安装文件下载便可。bootstrap
/Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini
中进行修改。/Applications/mat.app/Contents/MacOS
,执行./MemoryAnalyzer
命令,这种只能经过命令启动,不能经过图表启动。关于方案1,这篇文章讲得更细致:https://www.jianshu.com/p/9bbbe3c4cc8b后端
个人电脑是8C16G的,那理论上分析10G的堆文件没问题,可是MAT默认的配置没有这么大,须要在/Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini
文件中进行修改。以下图所示,我将个人MAT本身的运行时堆内存配置成了6G。网络
MAT的配置页面能够从Window——>Preferences找到,以下图所示。 app
MAT的通常配置有几个选项dom
Keep unreachable objects:若是勾选这个,则在分析的时候会包含dump文件中的不可达对象;
Hide the getting started wizard:隐藏分析完成后的首页,控制是否要展现一个对话框,用来展现内存泄漏分析、消耗最多内存的对象排序。
Hide popup query help:隐藏弹出查询帮助,除非用户经过F1或Help按钮查询帮助。
Hide Welcome screen on launch:隐藏启动时候的欢迎界面
Bytes Display:设置分析结果中内存大小的展现单位
能够看出,MAT不只支持HPROF文件的分析,还支持DTFJ文件的分析。通常sun公司系列的JVM生成的dump文件都是HPROF格式的,IBM的JVM生成的dump文件时DTFJ格式的。
Heap Dump是Java进程在某个时刻的内存快照,不一样JVM的实现的Heap Dump的文件格式可能不一样,进而存储的数据也可能不一样,可是通常来讲。
Heap Dump中主要包含当生成快照时堆中的java对象和类的信息,主要分为以下几类:
对象信息:类名、属性、基础类型和引用类型
类信息:类加载器、类名称、超类、静态属性
gc roots:JVM中的一个定义,进行垃圾收集时,要遍历可达对象的起点节点的集合
线程栈和局部变量:快照生成时候的线程调用栈,和每一个栈上的局部变量
Heap Dump中没有包含对象的分配信息,所以它不能用来分析这种问题:一个对象何时被建立、一个对象时被谁建立的。
Shallow heap是一个对象自己占用的堆内存大小。一个对象中,每一个引用占用8或64位,Integer占用4字节,Long占用8字节等等。
Retained set,对于某个对象X来讲,它的Retained set指的是——若是X被垃圾收集器回收了,那么这个集合中的对象都会被回收,同理,若是X没有被垃圾收集器回收,那么这个集合中的对象都不会被回收。
Retained heap,对象X的Retained heap指的时候它的Retained set中的全部对象的Shallow si的和,换句话说,Retained heap指的是对象X的保留内存大小,即因为它的存活致使多大的内存也没有被回收。
leading set,对象X可能不止有一个,这些对象统一构成了leading set。若是leading set中的对象都不可达,那么这个leading set对应的retained set中的对象就会被回收。通常有如下几种状况:
在下面这张图中,A和B是gc roots中的节点(方法参数、局部变量,或者调用了wait()、notify()或synchronized()的对象)等等。能够看出,E的存在,会致使G没法被回收,所以E的Retained set是E和G;C的存在,会致使E、D、F、G、H都没法被回收,所以C的Retined set是C、E、D、F、G、H;A和B的存在,会致使C、E、D、F、G、H都没法被回收,所以A和B的Retained set是A、B、C、E、D、F、G、H。
MAT根据堆上的对象引用关系构建了支配树(Dominator Tree),经过支配树能够很方便得识别出哪些对象占用了大量的内存,并能够看到它们之间的依赖关系。
若是在对象图中,从gc root或者x上游的一个节点开始遍历,x是y的必经节点,那么就能够说x支配了y(dominate)。
若是在对象图中,x支配的全部对象中,y的距离最近,那么就能够说x直接支配(immediate dominate)y。
支配树是基于对象的引用关系图创建的,在支配树中每一个节点都是它的子节点的直接支配节点。基于支配树能够很清楚得看到对象之间的依赖关系。
如今看个例子,在下面这张图中
在MAT中,gc roots的概念跟研究垃圾收集算法时候的概念稍微有点不一样。gc roots中的对象,是指那些能够从堆外访问到的对象的集合。若是一个对象符合下面这些场景中的一个,就能够被认为是gc roots中的节点:
java.util.*
开头的。synchronized(object)
或synchronized
方法。经过MAT生成dump文件
经过这个路径找到生成dump文件的对话框
选择一个进程,点击finish便可
jmap -dump:live,format=b,file=heap.bin <pid>
经过设置JVM参数自动生成
使用-XX:+HeapDumpOnOutOfMemoryError
这个JVM参数,在Java进程运行过程当中发生OOM的时候就会生成一个heapdump文件,并写入到指定目录,通常用-XX:HeapDumpPath=${HOME}/logs/test
来设置。
本号专一于后端技术、JVM问题排查和优化、Java面试题、我的成长和自我管理等主题,为读者提供一线开发者的工做和成长经验,期待你能在这里有所收获。