JVM-性能优化工具 MAT

这篇具有很好参考价值的文章主要介绍了JVM-性能优化工具 MAT。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、MAT下载和安装

1、概述

MAT(Memory Analyzer Tool)工具是一款功能强大的]ava堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。MAT是基于Eclipse开发的,不仅可以单独使用,还可以作为插件的形式嵌入在Eclipse中使用。是一款免费的性能分析工具,使用起来非常方便。

2、下载地址:

https://www.eclipse.org/mat/downloads.php

我目前电脑的JDK安装环境是1.8的,所以需要下载对应JDK1.8版本的MAT版本
JVM-性能优化工具 MAT,jvm,性能优化,python
JVM-性能优化工具 MAT,jvm,性能优化,python

3、安装

下载后解压,点击MemoryAnalyzer.exe进行启动
JVM-性能优化工具 MAT,jvm,性能优化,python

4、安装出现的报错问题

4.1、MAT版本和JDK版本不一致

问题描述:
要是直接下载最新版的MAT,可能需要高版本JDK才行。启动是需要JDK11或者更高的版本,我本地JDK版本是1.8,所以会报JDK版本不适合。
JVM-性能优化工具 MAT,jvm,性能优化,python
解决方法:
在MemoryAnalyzer.ini 中加入指定jdk的地址, (jdk不用安装直接下载 解压指定bin/javaw.exe就可)

-vm
D:/java/jdk1.8.0_211/binbin/javaw.exe
-vm
D:/java/jdk1.8.0_211/binbin/javaw.exe
-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.700.v20180518-1200
-vmargs
-Xmx1024m

4.2、堆dump文件较大、使用MAT打开的时候总是抛出 Java Heap Error

问题描述:
有时候线上产生的堆dump文件较大,如果你的hprof文件没有问题的话,使用MAT打开的时候总是抛出 Java Heap Error. 可能是默认的1024m内存不够用了。

解决办法:
找到MAT的安装目录,找到MemoryAnalyzer.ini 修改其中的-Xmx即可
JVM-性能优化工具 MAT,jvm,性能优化,python
将-Xmx1024m 调大即可
JVM-性能优化工具 MAT,jvm,性能优化,python

5、jmap命令拿到dump日志文件

jmap是Java虚拟机自带的一个命令行工具,可以用来生成JVM内存快照(Heap dump)文件。以下是使用jmap命令生成dump文件的步骤:

jmap -dump:format=b,file=heap.bin <pid>

通常情况下,在生产环境中使用jmap命令生成Heap dump文件时,建议把生成的文件下载到本地进行分析,以减少对生产环境的干扰。另外,在生成Heap dump文件时,一定要确保Java应用程序正常运行,否则可能会导致生成的文件不完整或者无法正确解析。

二、MAT工具排查分析OOM

1、故障现象:

集群应用服务器在高并发请求的情况下会不定时地因为响应超时而报警,但是很快又超时解除,恢复正常,如此反复,让运维人员非常苦恼。
原因分析: 来到一家新公司,一个重构项目的开发人员估计搞不动了,最后选择跑路,我的到来正好接盘了这个有好多bug的项目。配合测试功能测试完结束后,进行压测。发现查询接口只要并发一起来就会出现错乱的现象。先是排查原先写的代码是否有问题,没发现问题,然后我以为是脏读,调整的事务的隔离级别等等方法,发现还是解决不了。最后没办法在方法上加了一个synchronized锁,再进行压测时,虽然吞吐量不高,但是不会有报错的现象。等开始正式切换系统进行上线时。因为每天会有至少20w的查询量。只要某个时间段只要请求量很高就会出现连接超时的现象。当时也想到是因为加了synchronized造成高并发请求下,很多请求一直在等待,最后因为时间太久而造成的超时。所以我就下载了dump文件,使用MAT工具进行分析。果然是这个锁造成的。这是的我已经对代码稍微熟悉了,分析什么造成的错乱现象。发现代码有一处用到了共享变量,造成每次高并发去请求出现的错乱现象。我当时心里。。。
JVM-性能优化工具 MAT,jvm,性能优化,python
参考https://blog.csdn.net/cl939974883/article/details/124581664 文档,确实是synchronized造成的
JVM-性能优化工具 MAT,jvm,性能优化,python
下面详说一下MAT如何分析dump文件

2、MAT 分析 OOM 问题通常思路:

  1. 通过支配树功能或直方图功能查看消耗内存最大的类型,来分析内存泄露的大概原因;
  2. 查看那些消耗内存最大的类型、详细的对象明细列表,以及它们的引用链,来定位内存泄露的具体点;
  3. 配合查看对象属性的功能,可以脱离源码看到对象的各种属性的值和依赖关系,帮助我们理清程序逻辑和参数;
  4. 辅助使用查看线程栈来看 OOM 问题是否和过多线程有关,甚至可以在线程栈看到 OOM 最后一刻出现异常的线程。

3、使用MAT定位问题:

  • 定位问题方式一:

    现在有一个OOM后得到的堆转储文件 java_pid29569.hprof,现在要使用 MAT 的直方图支配树线程栈OQL 等功能来分析此次 OOM 的原因。

    首先,用 MAT 打开后先进入的是概览信息界面,可以看到整个堆是 437.6MB:
    JVM-性能优化工具 MAT,jvm,性能优化,python
    那么,这 437.6MB 都是什么对象呢?

    如图所示,工具栏的第二个按钮可以打开直方图,直方图按照类型进行分组,列出了每个类有多少个实例,以及占用的内存。可以看到,char[]字节数组占用内存最多,对象数量也很多,结合第二位的 java.lang.String 类型对象数量也很多,大概可以猜出(String 使用 char[]作为实际数据存储)程序可能是被字符串占满了内存,导致 OOM。
    JVM-性能优化工具 MAT,jvm,性能优化,python
    char[]上点击右键,选择 List objects->with incoming references,就可以列出所有的 char[]实例,以及每个 char[]的整个引用关系链:
    JVM-性能优化工具 MAT,jvm,性能优化,python
    随机展开一个 char[],如下图所示:
    JVM-性能优化工具 MAT,jvm,性能优化,python
    接下来,我们按照红色框中的引用链来查看,尝试找到这些大 char[]的来源:

  • 在①处看到,这些 char[]几乎都是 10000 个字符、占用 20000 字节左右(char 是 UTF-16,每一个字符占用 2 字节);

  • 在②处看到,char[]被 Stringvalue 字段引用,说明 char[]来自字符串;

  • 在③处看到,StringArrayListelementData 字段引用,说明这些字符串加入了一个 ArrayList 中;

  • 在④处看到,ArrayList 又被 FooServicedata 字段引用,这个 ArrayList 整个 RetainedHeap 列的值是 431MB。

  • 左侧的蓝色框可以查看每一个实例的内部属性,图中显示 FooService 有一个 data 属性,类型是 ArrayList

    Retained Heap(深堆):代表对象本身和对象关联的对象占用的内存;

    Shallow Heap(浅堆):代表对象本身占用的内存。
    比如,我们的 FooService 中的 data 这个 ArrayList 对象本身只有 16 字节,但是其所有关联的对象占用了 431MB 内存。这些就可以说明,肯定有哪里在不断向这个 List 中添加 String 数据,导致了 OOM。

    如果我们希望看到字符串完整内容的话,可以右键选择 Copy->Value,把值复制到剪贴板或保存到文件中:
    JVM-性能优化工具 MAT,jvm,性能优化,python
    这里,我们复制出的是 10000 个字符 a(下图红色部分可以看到)。
    看到这些,我们已经基本可以还原出真实的代码是怎样的了,定位到了问题代码。

  • 定位问题方式二:
    其实,我们之前使用直方图定位 FooService,已经走了些弯路。你可以点击工具栏中第三个按钮(下图左上角的红框所示)进入支配树界面。这个界面会按照对象的 Retained Heap 倒序直接列出占用内存最大的对象。
    JVM-性能优化工具 MAT,jvm,性能优化,python
    可以看到,第一位就是 FooService,整个路径是 FooSerice->ArrayList->Object[]->String->char[](蓝色框部分),一共有 21523 个字符串(绿色方框部分)。通常使用这种方式可以一步到位的定位出问题所在。

  • 借助MAT寻到具体问题原因
    我们就从内存角度定位到 FooService 是根源了。那么,OOM 的时候,FooService 是在执行什么逻辑呢?

    为解决这个问题,我们可以点击工具栏的第五个按钮(下图红色框所示)。打开线程视图,首先看到的就是一个名为 main 的线程(Name 列),展开后果然发现了 FooService
    JVM-性能优化工具 MAT,jvm,性能优化,python
    先执行的方法先入栈,所以线程栈最上面是线程当前执行的方法,逐一往下看能看到整个调用路径。

  • 因为我们希望了解 FooService.oom() 方法,看看是谁在调用它,它的内部又调用了谁,所以选择以 FooService.oom() 方法(蓝色框)为起点来分析这个调用栈。

  • 往下看整个绿色框部分,oom() 方法被 OOMApplicationrun 方法调用,而这个 run 方法又被 SpringAppliction.callRunner 方法调用。

  • 看到参数中的 CommandLineRunner 你应该能想到,OOMApplication 其实是实现了 CommandLineRunner 接口,所以是 SpringBoot 应用程序启动后执行的。

  • FooService 为起点往上看,从紫色框中的 CollectorsIntPipeline,大概也可以猜出,这些字符串是由 Stream 操作产生的。

  • 再往上看,可以发现在 StringBuilderappend 操作的时候,出现了 OutOfMemoryError 异常(黑色框部分),说明这这个线程抛出了 OOM 异常。

    我们看到,整个程序是 Spring Boot 应用程序,那么 FooService 是不是 SpringBean 呢,又是不是单例呢?

    如果能分析出这点的话,就更能确认是因为反复调用同一个 FooServiceoom 方法,然后导致其内部的 ArrayList 不断膨胀。

    点击工具栏的第四个按钮(如下图红框所示),来到 OQL 界面。在这个界面,我们可以使用类似 SQL 的语法,在 dump 中搜索数据(你可以直接在 MAT 帮助菜单搜索 OQL Syntax,来查看 OQL 的详细语法)。
    JVM-性能优化工具 MAT,jvm,性能优化,python
    比如,输入如下语句搜索 FooService 的实例:

    SELECT * FROM org.geekbang.time.commonmistakes.troubleshootingtools.oom.FooService
    

    JVM-性能优化工具 MAT,jvm,性能优化,python
    可以看到只有一个实例,然后我们通过 List objects 功能搜索引用 FooService 的对象:
    JVM-性能优化工具 MAT,jvm,性能优化,python
    可以看到,一共两处引用:

  • 第一处是,OOMApplication 使用了 FooService

  • 第二处是一个 ConcurrentHashMap。可以看到,这个 HashMapDefaultListableBeanFactorysingletonObjects 字段,可以证实 FooServiceSpring 容器管理的单例的 Bean

4、结论

到现在为止,虽然没看程序代码,但是已经大概知道程序出现 OOM 的原因和大概的调用栈了。再贴出程序来对比一下,果然和我们看到得一模一样:

@SpringBootApplication
public class OOMApplication implements CommandLineRunner {
    @Autowired
    FooService fooService;
    public static void main(String[] args) {
        SpringApplication.run(OOMApplication.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        //程序启动后,不断调用Fooservice.oom()方法
        while (true) {
            fooService.oom();
        }
    }
}
@Component
public class FooService {
    List<String> data = new ArrayList<>();
    public void oom() {
        //往同一个ArrayList中不断加入大小为10KB的字符串
        data.add(IntStream.rangeClosed(1, 10_000)
                .mapToObj(__ -> "a")
                .collect(Collectors.joining("")));
    }
}

到这里,我们使用 MAT 工具从对象清单、大对象、线程栈等视角,分析了一个 OOM 程序的堆转储。可以发现,有了堆转储,几乎相当于拿到了应用程序的源码 + 当时那一刻的快照,OOM 的问题无从遁形。

三、jvm-jps、jinfo、jstat、jstack、jmap 基本使用

给系统定位问题的时候,知识经验是基础,应用数据是依据,工具是手段,在jvm中,我们常见的数据包括: 运行日志、堆栈信息、GC信息、线程快照(threaddump/javacode)、堆快照(heapdump/hporf),jdk提供给我们了很实用的工具来分析,定位解决这些问题,这些工具包含于jdk中,并且以java实现,方便在不同的环境中不用安装其他依赖库即可使用,很是方便。下面分别介绍 jps、jinfo、jstat、jstack、jmap,本文使用的jdk版本为1.8.0_11

1、jps ( jvm process status tool ) 虚拟机进程工具

配置项 作用
-q 忽略主类的名称,只输出pid
-m 输出启动类main函数的参数
-l 输出主类名,如果进程执行的为jar,则输出jar路径
-v 输出具体进程启动时jvm参数

1.命名格式

jps [options] pid

2.常用方式

  • jps -lv : 输出启动类名与启动时jvm参数,可以方便的看到各个tomcat的自定义参数配置
  • jps -lv |grep project_name : 在上述基础上过滤出自己想要查看的项目的信息

2、jinfo ( configuration info for java ) 显示虚拟机配置信息

1.常用用法

  • jinfo pid : 显示jvm系统属性与vm参数信息
  • jinfo -flags pid : 显示jvm vm参数信息,如最大最小堆,默认堆,垃圾收集器参数等
  • jinfo -sysprops pid : 显示jvm系统属性
  • jinfo -flag : 显示特定vm参数值,例如 jinfo -flag MaxHeapSize pid 输出pid的最大堆内存

3、jstat ( jvm statistics monitoring tool) 收集虚拟机各方面运行数据

1、语法格式

jstat [ option pid [interval[s|ms] [count]]]

说明: interval 表示循环时间间隔,默认单位为ms,可以在直接使用s/ms指定单位,如 60ms/1s, count 表示输出几次 例:

jstat gc pid 1s 20

每1s查询一次gc情况,查询20次

2、option 详解(主要分三类:类装载、垃圾收集、运行期编译状况)

配置项 作用
-class 监视类装载、卸载数量、总空间以及类装载所耗费的时间
-gc 监视Java堆,包括Eden区、两survivor区、老年代、永久代等的容量、已用空间、GC时间合计等
-gccapacity 与-gc基本相同,但关注点为Java堆各个区域使用到的最大、最小空间
-gcutil 与-gc基本相同,但关注点为Java堆各个区域已使用空间占总空间的百分比
-gccause 与-gcutil功能相同,但会额外输出导致上一次GC产生的原因
-gcnew 监控新生代GC情况
-gcnewcapacity 与-gcnew基本相同,但关注最大,最小空间
-gold 监控老年代GC情况
-goldcapacity 与-gcold基本相同,但关注最大,最小空间
-compiler 输出被JIT编译过的方法、耗时等信息
-printcomplilation 输出已经被JIT编译的方法

3、查看类装载卸载情况 jstat -class pid

属性 释义
Loaded 装载总数量
Bytes 装载总大小
Unloaded 卸载类的数量
Time 加载和卸载类总共的耗时

4、查看GC情况 jstat -gc pid

属性 释义
S0C 新生代survivor0容量
S1C 新生代survivor1容量
S0U 新生代survivor0已使用大小
S1U 新生代survivor1已使用大小
EC 新生代eden区容量
EU 新生代eden区已使用大小
OC 老年代容量
OU 老年代已使用大小
MC 元数据容量,即方法区容量
MU 元数据已使用空间
CCSC 压缩类空间大小
CCSU 压缩类空间使用大小
YGC 新生代gc次数(young gc)
YGCT 新生代gc时间(s)
FGC 老生代gc次数(full gc)
GCT 总的gc时间,包括young gc和full gc

5、查看GC情况,以百分比显示

jstat -gcutil pid

6、查看新生代GC情况

jstat -gcnew pid
属性 释义
S0C 新生代survivor0容量
S1C 新生代survivor1容量
S0U 新生代survivor0已使用大小
S1U 新生代survivor1已使用大小
TT 对象在新生代存活的次数
MTT 对象在新生代存活的最大次数
DSS 期望的幸存区大小
EC eden区大小
EU eden区已使用大小
YGC young gc次数
YGCT young gc 时间 (秒)

7、查看老年代GC情况

jstat -gcold pid

8、查看各空间容量

jstat -gccapacity pid
属性 释义
NGCMN 新生代最小容量
NGCMX 新生代最大容量
NGC 当前新生代容量
S0C survivor0大小
S1C survivor0大小
EC EDEN区大小
OGCMN 老年代最小容量
OGCMX 老年代最大容量
OGC 当前老年代大小
MCMN 元数据最小容量
MCMX 元数据最大容量
CCSMN 最小压缩类空间大小
CCSMX 最大压缩类空间大小
CCSC 当前压缩类空间大小)

9、查看编译情况

jstat -compiler pid

4、jmap ( memory map for java ) 虚拟机堆快照工具

1、常用用法

  • jmap -heap pid 查看当前jvm heapdump与垃圾收集器的使用情况
  • jmap -dump:format=b,file=/temp/filename.hprof pid 转储堆快照,生成hprof文件到指定路径
  • jmap -histo pid 列出当前heap中对象状况,附字节码与java对象映射表

5、jstack ( stack trace for java ) 虚拟机线程快照工具

效果演示: 会显示所有线程的各种信息,可以用来排查死锁,或线程长时间停滞的问题…文章来源地址https://www.toymoban.com/news/detail-679395.html

到了这里,关于JVM-性能优化工具 MAT的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM性能优化 —— 类加载器,手动实现类的热加载

    每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的”.class”文件,并创建对应的class对象,将c

    2024年02月08日
    浏览(37)
  • 【JVM 监控工具】性能诊断--JProfiler的使用

    性能诊断是软件工程师在日常工作中需要经常面对和解决的问题,在用户体验至上的今天,解决好应用的性能问题能带来非常大的收益。Java 作为最流行的编程语言之一,其应用性能诊断一直受到业界广泛关注。可能造成 Java 应用出现性能问题的因素非常多,例如线程控制、

    2024年02月08日
    浏览(59)
  • JVM性能监控之命令行工具全解

    性能诊断是软件工程师在日常工作中需要经常面对和解决的问题,在用户体验至上的今天,解决好应用的性能问题能带来非常大的收益。 Java作为最流行的编程语言之一,其应用性能诊断一直受到业界的广泛关注,可能造成Java应用出现性能问题的因素非常多,例如线程控制、

    2023年04月08日
    浏览(48)
  • JVM逃逸分析原理解析:优化Java程序性能和内存利用效率

    在Java开发中,性能和内存利用效率一直是开发者关注的焦点。为了提高Java程序的执行效率,JVM引入了逃逸分析技术。本文将详细解析JVM逃逸分析的原理,帮助读者深入理解其工作机制。 逃逸分析是一种用于确定对象在方法的生命周期内是否逃逸出方法外部范围的技术。在

    2024年01月20日
    浏览(62)
  • “深入探索JVM:解析Java虚拟机的工作原理与性能优化“

    标题:深入探索JVM:解析Java虚拟机的工作原理与性能优化 摘要:本文将深入探讨Java虚拟机(JVM)的工作原理和性能优化。我们将首先介绍JVM的基本组成和工作流程,然后重点讨论JVM内存管理、垃圾回收算法以及性能优化的几个关键方面。最后,我们将通过示例代码演示如何

    2024年02月11日
    浏览(51)
  • 【Jvm】性能调优(上)线上问题排查工具汇总

    产品闭环 产品闭环是能够让 用户主动迭代促进产品发展的方式 。例如一些内容产品,比如 糗事百科 ,种子用户 产出高质量内容 ,举报与赞起到 筛选内容 ,提高内容质量的作用, 内容质量的提升有助于吸引更多用户 。 这就是产品闭环, 产品给予用户需求解决方法,用户

    2024年02月20日
    浏览(49)
  • 【业务功能篇86】微服务-springcloud-系统性能压力测试-jmeter-性能优化-JVM参数调优

      压力测试是给软件不断加压,强制其在极限的情况下运行,观察它可以运行到何种程度,从而发现性能缺陷,是通过搭建与实际环境相似的测试环境,通过测试程序在同一时间内或某一段时间内,向系统发送预期数量的交易请求、测试系统在不同压力情况下的效率状况,

    2024年02月10日
    浏览(57)
  • JVM:性能监控工具分析和线上问题排查实践

    在日常开发过程中,多少都会碰到一些jvm相关的问题,比如: 内存溢出、内存泄漏、cpu利用率飙升到100%、线程死锁、应用异常宕机 等。 在这个日益内卷的环境,如何运用好工具分析jvm问题,成为每个java攻城狮必备的技能。所以白梦特意整理了 jdk自带分析工具的使用 ,以及

    2024年01月19日
    浏览(45)
  • 性能调优篇 二、Jvm监控及诊断工具-命令行篇

    性能诊断是软件工程师在日程生活中需要经常面对和解决的问题 Java作为最流行的编程语言之一,其应用性能诊断一直收到业内广泛关注。造成Java应用出现性能问题的因素非常多,例如线程控制,磁盘读写,数据库访问,网络io,垃圾收集等。 想要定位这些问题,一款优秀的

    2024年02月11日
    浏览(46)
  • Java线上故障排查(CPU、磁盘、内存、网络、GC)+JVM性能调优监控工具+JVM常用参数和命令

    根据服务部署和项目架构,从如下几个方面排查: (1)运用服务器:排查内存,cpu,请求数等; (2)文件图片服务器:排查内存,cpu,请求数等; (3)计时器服务器:排查内存,cpu,请求数等; (4)redis服务器:排查内存,cpu,连接数等; (5)db服务器:排查内存,cpu,连接数

    2024年02月07日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包