JVM提供了自动内存管理机制,使程序员的开发变得更加容易,而在实践中这个目标也达到了,日常开发通常不需要你担心为对象释放内存的问题。大多数JVM 使用跟踪算法来确定对象是否应该被回收,因此JVM 只能回收从gc root 无法到达的对象。
当您使用大对象、集合对象或第三方包中的资源而忘记及时释放它们时,就会发生JVM 内存泄漏和内存浪费。因此,如果你想成为一名更高级的Java开发工程师,你需要了解常见的故障排除方法和工具。本系列文章介绍——MAT(Memory Aanosis Tool),一个JVM堆内存分析的工具。
MAT 的官方网站为:https://www.eclipse.org/mat/——MAT 是一个高性能、功能丰富的Java 堆内存分析工具,可用于排除内存泄漏和内存浪费问题。
1.安装及安装设置
1.1 Mac安装
MAT 支持两种安装方法。一种是“单机版”。这意味着用户不需要安装Eclipse IDE环境。另一种意味着MAT 作为单独的Eclipse RCP 应用程序运行。其MAT 还可以作为Eclipse IDE 的一部分与现有开发平台集成。
这里我们考虑单独安装。在等待下载页面,选择您要下载的安装文件的macOS 版本。
安装过程中遇到的陷阱
系统默认工作空间是只读的,可以更换。启动时立即报告错误。如何修改文件/Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini?
启动后UI界面无响应。请参阅https://www.eclipse.org/forums/index.php/t/1090889/。我已经多次遇到过这个问题。
1.2 遮罩设置
设置mat堆内存大小
我的电脑是8C16G,所以理论上分析10G堆文件没有问题,但是MAT的默认配置没有那么大,所以我需要在/Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini中更改为需要。文件。我将MAT自带的运行时堆内存配置为6G,如下图所示。
配置MAT 使用
MAT配置页面可以在Window——Preferences下找到,如下图所示。
MAT 的常规配置有多个选项
保留无法访问的对象:如果选中,则在分析过程中将包含转储文件中无法访问的对象。 隐藏入门向导:控制分析完成后是否隐藏主页并显示内存泄漏对话框。对消耗最多内存的对象进行排序。隐藏弹出查询帮助:隐藏弹出查询帮助,除非用户使用F1 或“帮助”按钮查询帮助。 Hide Welcome screen on launch:隐藏启动时的欢迎屏幕Bytes Display:设置分析结果中内存大小的显示单位。可以看到MAT不仅支持解析HPROF文件,还支持解析DTFJ文件。一般来说,Sun系列JVM生成的dump文件是HPROF格式,IBM系列JVM生成的dump文件是DTFJ格式。
2. 基本思想
堆转储
堆转储是Java 进程在某个时间点的内存快照。一般来说,JVM 实现的堆转储的文件格式可能有所不同,并且保存的数据也可能有所不同。
堆转储主要包含生成快照时堆中Java 对象和类的信息,主要分为以下几类:
对象信息:类名、属性、基类型、引用类型类信息:类加载器、类名、超类、静态属性gc root:定义在JVM 中执行垃圾回收时,可达对象的起始节点必须是:遍历的线程堆栈和局部变量集合:生成快照时的线程调用堆栈和每个堆栈的局部变量不包含对象分配信息,无法用于分析此问题。对象创建日期,对象创建者。
浅堆和保留堆
浅堆是对象本身占用的堆内存量。对于对象来说,每个引用占用8或64位,一个Integer占用4个字节,一个Long占用8个字节,依此类推。
保留集。对于对象X,其保留集引用——。在这种情况下,该集合中的任何对象都不会被回收。
保留堆。对象X 的保留堆是指其保留集中所有对象的浅si 之和。换句话说,保留堆是指对象保留的内存大小。而且,它没有被回收。
在一个前导集合中,可能存在多个对象X,它们共同构成了前导集合。如果第一组中没有可达对象,则回收第一组对应的保留集中的对象。常见情况包括:
特定类的所有实例对象。该类对象是第一个对象。该类加载器对象是一组对象,必须传递由特定类记录器加载的所有类以及这些类的实例对象。下图中,A和B是gc根节点(方法参数、局部变量或调用wait()、notify()或synchronized的对象)。 ())这样的。我们看到E的存在阻止了G被回收,因此E的保留集是E和G,C的存在阻止了E、D、F、G和H被回收。保留的C. C、E、D、F、G、H。如果A、B存在,则C、E、D、F、G、H不会被回收。 A和B是A、B、C、E、D、F、G、H。
统治者树
MAT 根据堆上的对象引用构建支配树。通过支配树,您可以轻松识别占用大量内存的对象并查看对象之间的依赖关系。
在对象图中,如果遍历从gc 根或x 的上游节点开始,并且x 是y 的必要节点,则称x 支配y。
在对象图中,如果y 是受x 支配的所有对象中最接近的,则称x 直接支配y。
优势树是根据对象的参考图建立的。支配树中的每个节点都是其子节点的直接支配节点。基于支配树,可以清楚地看到对象之间的依赖关系。
请参阅下图中的示例。
x节点的子树是x支配的所有节点的集合,形式上也是x的保留集。如果x是y的直接主导节点,则y的主导节点不是一对一的。一致。 垃圾收集根
在MAT 中,GC 根的概念与研究垃圾收集算法时略有不同。 gc根中的对象是指可以从堆外部访问的对象的集合。如果一个对象属于以下场景之一,则可以将其视为gc 根中的节点:
系统类:由引导类加载器加载的类(例如rt.jar)。所有内部类包名称均以java.util.* 开头。 JNI local:本机代码中的局部变量,例如用户编写的JNI代码或JVM内部代码。 JNI全局变量:本机代码中的全局变量,例如用户编写的JNI代码或JVM内部代码。线程块:当前活动线程锁引用的对象。线程:实时线程繁忙监视器:使用wait()、notify() 或同步关键字修改的代码称为——,例如同步(对象)或同步方法。 Java local:局部变量。例如,在运行线程堆栈上创建的函数或对象的输入参数。 Native stack:本机代码的输入或输出参数,例如用户定义的JNI代码或JVM内部代码。文件/网络IO 方法或反射方法的参数。 Finalized:终结队列中等待终结器对象执行的对象。未终结:finalize方法已被重载,但对象尚未进入终结队列。 Unreachable:从任何gc 根节点都无法访问的对象。否则,这些对象将被视为MAT 中的根节点。 Java栈帧:Java栈帧。用于存储局部变量。仅当解析转储文件时,Java 堆栈帧才被视为对象。未知:不存在根类型的对象。某些转储文件(例如IBM 的便携式堆转储)没有根信息。 3. 获取转储文件
通过MAT生成转储文件,通过该路径找到生成转储文件的对话框。选择 进程并单击完成。
使用jmap 命令生成转储文件。 命令格式:jmap -dump:live,format=b,file=heap.bin pid 注意:如果要在堆转储中保留无法访问的对象,则必须删除“:live”。即使用命令“jmap -dump,format=b,file=heap.bin pid”。该命令是通过设置JVM参数自动生成的,当Java运行出现OOM时,使用-XX:+HeapDumpOnOutOfMemoryError JVM参数。此过程生成堆转储文件并将其写入指定目录。通常使用-XX:HeapDumpPath=${HOME}/logs/test 进行设置。
版权声明:本文由今日头条转载,如有侵犯您的版权,请联系本站编辑删除。