JVM离线分析-使用MAT分析dump堆文件

1. MAT(Memory Analyzer Tool)的介绍

官方介绍

The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption. Use the Memory Analyzer to analyze productive heap dumps with hundreds of millions of objects, quickly calculate the retained sizes of objects, see who is preventing the Garbage Collector from collecting objects, run a report to automatically extract leak suspects.

简要说明:MAT用来分析jvm的内存信息,内存信息包含两方面

  • 所有的对象信息:包括对象实例、成员变量、存储于栈中的基本类型值和存储于堆中的其他对象的引用值
  • 所有的类信息: 包括classloader、类名称、父类、静态变量 GCRoot到所有的这些对象的引用路径线程信息,包括线程的调用栈及此线程的线程局部变量(TLS)

2. MAT安装:略

3. MAT使用场景

  • 内存溢出,JVM堆区或方法区放不下存活及待申请的对象。如:高峰期系统出现 OOM(Out of Memory)异常,需定位内存瓶颈点来指导优化。
  • 内存泄漏,不会再使用的对象无法被垃圾回收器回收。如:系统运行一段时间后出现 Full GC,甚至周期性 OOM 后需人工重启解决。
  • 内存占用高。如:系统频繁 GC ,需定位影响服务实时性、稳定性、吞吐能力的原因。

4. MAT 的工作原理以及核心功能

对 dump 文件建立多种索引,并基于索引来实现内存分布、对象间依赖、对象状态、条件检索这四大核心功能,并通过可视化展现辅助 Developer 精细化了解 JVM 堆内存全貌。

5. MAT 核心产品能力概括如下:

5.1 内存分布

  • 全局概览信息:堆内存大小、对象个数、类的个数、类加载器的个数、GC root 个数、线程概况等全局统计信息。
  • Histogram:罗列每个类实例的内存占比,包括自身内存占用量(Shallow Heap)及支配对象的内存占用量(Retain Heap),支持按 package、class loader、super class、class 聚类统计,最常用的功能之一。
  • Dominator tree:按对象的 Retain Heap 排序,也支持按多个维度聚类统计,最常用的功能之一。
  • Leak Suspects:直击引用链条上占用内存较多的可疑对象,可解决一些基础问题,但复杂的问题往往帮助有限。
  • Top Consumers:展现哪些类、哪些 class loader、哪些 package 占用最高比例的内存。

5.2 对象间依赖

  • References:提供对象的外部引用关系、被引用关系。通过任一对象的直接引用及间接引用详情(主要是属性值及内存占用),进而提供完善的依赖链路详情。
  • Dominator tree:支持按对象的 Retain Heap 排序,并提供详细的支配关系,结合 references 可以实现大对象快速关联分析;
  • Thread overview:展现转储 dump 文件时线程栈帧等详细状态,也提供各线程的 Retain Heap 等关联内存信息。
  • Path To GC Roots:提供任一对象到 GC Root 的链路详情,帮助了解不能被 GC 回收的原因。

5.3 对象状态

  • 最核心的是通过 inspector 面板提供对象的属性信息、类继承关系信息等数据,协助分析内存占用高与业务逻辑的关系。
  • 集合状态的检测,如:通过 ArrayList 或数组的填充率定位空集合空数组造成的内存浪费、通过 HashMap 冲突率判定 hash 策略是否合理等。

5.4 条件检索

  • OQL:提供一种类似于SQL的对象(类)级别统一结构化查询语言。(举例,查找 size=0 且未使用过的 ArrayList:select * from java.util.ArrayList where size=0 and modCount=0;查找所有的String的length属性的:select s.length from instanceof String s)
  • 内存分布及对象间依赖的众多功能,均支持按字符串检索、按正则检索等操作。
  • 按虚拟内存地址寻址,根据对象的十六进制地址查找对象。

[图片]

6. 模拟OOM,dump堆文件

public class Th {

    public static void main(String[] args) throws InterruptedException {

        new Thread(() -> {
            List<OOMObject> list = new ArrayList<>();
            while (true) {
                System.out.println("....................");
                list.add(new OOMObject());
            }
        }).start();

        while (true) {
            System.out.println(Thread.currentThread().getName() + " continuing...");
            Thread.sleep(1000L);
        }
        
    }
}

class OOMObject {
}

分析堆文件

6.1总览

[图片]

  • 全局概览信息,堆内存大小、类数量、实例数量、Class Loader数量。
  • Unreachable Object Histogram,展现转储快照时可被回收的对象信息(一般不需要关注,除非 GC 频繁影响实时性的场景分析才用到)
  • Biggest Objects by Retained Size,展现经过统计过的哪几个实例所关联的对象占内存总和较高,以及具体占用的内存大小,一般相关代码比较简单情况下,往往可以直接分析具体的引用关系异常,如内存泄漏等。此外也包含了最大对象和链接支持继续深入分析。
  • GC Root:GC Root 代表通过可达性分析来判定 JVM 对象是否存活的起始集合。JVM 采用追踪式垃圾回收(Tracing GC)模式,从所有 GC Roots 出发通过引用关系可以关联的对象就是存活的(所以不可回收),其余的不可达的对象(Unreachable object:如果无法从 GC Root 找到一条引用路径能到达某对象,则该对象为Unreachable object)可以回收。一般是未执行完的线程自身,或运行线程的调用栈上的对象(如局部变量、方法参数)、System class loader 加载的类、native code 保留的活动对象等。

6.2 直方图

[图片]
MAT的直方图和jmap的-histo命令一样,都能够展示各个类的实例数目以及这些实例的Shallowheap总和

6.3 thread overview

[图片]
with outgoing references:此对象引用了哪些对象,
with incoming references:此对象被谁引用,

6.4 Shallow Heap 和 Retained Heap

  • Shallow Heap:其自身在内存中的大小
  • Retained Heap:指的就是在垃圾回收特定对象时将释放的内存量
    当前深堆大小 = 当前对象的浅堆大小 + 对象中所包含对象的深堆大小,如果对象包括的对象还有对象的话,也要算最里层的对象的大小
  • 参考:https://cloud.tencent.com/developer/article/1530224

代码示例:


import java.util.ArrayList;
import java.util.List;

/**
 * 有一个学生浏览网页的记录程序,它将记录 每个学生访问过的网站地址。
 * 它由三个部分组成:Student、WebPage和StudentTrace三个类
 * -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=C:\Users\zishi\Desktop\oomdump\abc\student.hprof
 *
 */
public class StudentTrace {
    static List<WebPage> webpages = new ArrayList<WebPage>();

    public static void createWebPages() {
        for (int i = 0; i < 100; i++) {
            WebPage wp = new WebPage();
            wp.setUrl("http://www." + Integer.toString(i) + ".com");
            wp.setContent(Integer.toString(i));
            webpages.add(wp);
        }
    }

    public static void main(String[] args) {
        createWebPages();//创建了100个网页
        //创建3个学生对象
        Student st3 = new Student(3, "Tom");
        Student st5 = new Student(5, "Jerry");
        Student st7 = new Student(7, "Lily");

        for (int i = 0; i < webpages.size(); i++) {
            if (i % st3.getId() == 0)
                st3.visit(webpages.get(i));
            if (i % st5.getId() == 0)
                st5.visit(webpages.get(i));
            if (i % st7.getId() == 0)
                st7.visit(webpages.get(i));
        }
        webpages.clear();
        System.gc();
    }
}


package com.zishi.jvm;

import java.util.ArrayList;
import java.util.List;

public class Student {
    private int id;
    private String name;
    private List<WebPage> history = new ArrayList<>();

    public Student(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<WebPage> getHistory() {
        return history;
    }

    public void setHistory(List<WebPage> history) {
        this.history = history;
    }

    public void visit(WebPage wp) {
        if (wp != null) {
            history.add(wp);
        }
    }
}
public class WebPage {
    private String url;
    private String content;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

main方法启动参数:
-XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=C:\Users\zishi\Desktop\oomdump\abc\student.hprof
[图片]

6.5 Dominator Tree(需进一步完善)

[图片]

6.6 OQL(需进一步完善)

OQL:提供一种类似于SQL的对象(类)级别统一结构化查询语言
[图片]
参考帮助文档

6.6 常见内存分析工具对比

在这里插入图片描述

注 1: Dump 文件包含快照被转储时刻的 Java 对象 在堆内存中的分布情况,但快照只是瞬间的记录,所以不包含对象在何时、在哪个方法中被分配这类信息。
注 2: 一般堆外内存溢出排查可结合 gperftools 与 btrace 排查,再开一篇介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/115729.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件设计模式原则(二)开闭原则

继续讲解第二个重要的设计模式原则——开闭原则~ 一.定义 开闭原则&#xff0c;在面向对象编程领域中&#xff0c;规定“软件中的对象&#xff08;类&#xff0c;模块&#xff0c;函数等等&#xff09;应该对于扩展是开放的&#xff0c;但是对于修改是封闭的”&#xff0c;这意…

springboot中使用redis管理session

前言 使用软件&#xff1a; redis&#xff1a; linux版本下载 windows版本下载 安装redis 下载redis http://download.redis.io/releases/ 源码安装redis&#xff08;ubuntu&#xff09; #将指定版本的redis上传到服务器#解压 sudo tar -xzvf redis-6.2.4.tar.gzcd re…

牛客项目(五)-使用kafka实现发送系统通知

kafka入门以及与spring整合 Message.java import java.util.Date;public class Message {private int id;private int fromId;private int toId;private String conversationId;private String content;private int status;private Date createTime;public int getId() {retur…

Springboot搭建微服务案例之Eureka注册中心

一、父工程依赖管理 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org…

服务器经常被攻击的原因

很多中小型企业都是选择虚拟主机服务器&#xff0c;是把一个服务器分成很多个给很多企业一起共用&#xff0c;可能同一个 IP服务器上就有很多个不同企业的网站&#xff0c;这个时候如果跟你同一个IP服务器的网站遭到DDoS攻击&#xff0c;就很有可能会影响到你的网站也无法正常访…

学习笔记二十七:K8S控制器Statefulset入门到企业实战应用

这里写目录标题 Statefulset控制器&#xff1a;概念、原理解读Statefulset资源清单文件编写技巧查看定义Statefulset资源需要的字段查看statefulset.spec字段如何定义&#xff1f;查看statefulset的spec.template字段如何定义 Statefulset使用案例&#xff1a;部署web站点State…

apollo云实验:定速巡航场景仿真调试

定速巡航场景仿真调试 概述启动仿真环境仿真系统修改默认巡航速度 实验目的福利活动 主页传送门&#xff1a;&#x1f4c0; 传送 概述 自动驾驶汽车在实现落地应用前&#xff0c;需要经历大量的道路测试来验证算法的可行性和系统的稳定性&#xff0c;但道路测试存在成本高昂、…

webgl入门-基础三角形绘制

背景 最近工作上频繁接触webgl&#xff0c;因为不熟悉每每看到shader中的语法总感觉脑袋大&#xff0c;所以打算开始从零学习一下webgl&#xff0c;文章只做记录学习历程&#xff0c;那就直接开始吧&#xff01; 开始 可以配合着这个文章食用。 我还是对webgl有一些概念的&…

Java 8 新特性 Stream 的使用场景(不定期更新)

方便在写代码的过程中直接使用&#xff0c;好记性不如好文章&#xff0c;直接 CV 改了直接用。提高 办&#xff08;摸&#xff09;公&#xff08;鱼&#xff09;效&#xff08;时&#xff09;率&#xff08;间&#xff09;&#xff0c; 不然就直接问 GPT 也不是说不行。 只符合…

AI:52-基于深度学习的垃圾分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

WPF布局控件之DockPanel布局

前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 概述&#xff1a; DockPanel 位置子控件基于子 Dock 属性&#xff0c;你有 4 个选项停靠&#xff0c;左 (默认) &…

接口自动化测试难点:数据库验证解决方案 百分之90人不知道

接口自动化中的数据库验证&#xff1a;确保数据的一致性和准确性 接口自动化测试是现代软件开发中不可或缺的一环&#xff0c;而数据库验证则是确保接口返回数据与数据库中的数据一致性的重要步骤。本文将介绍接口自动化中的数据库验证的原理、步骤以及示例代码&#xff0c;帮…

最新版星火官方搬运工具6.0,高级搬运,100%过原创,短视频上热门搬运软件黑科技【搬运脚本+使用技术教程】

软件介绍&#xff1a; 高级搬运&#xff0c;条条过原创 短视频暴力热门搬运黑科技 自研摄像头内录突破性技术6.0 无需任何繁琐准备工作安装即用 无需复杂售后培训看教程即可学会 直装直用自研技术更好卖 无需root 无需框架 更方便 无需xposed 无需vcam更安全 适配99%以…

SaveToDisk属性

大家好&#xff0c;才是真的好。 Domino Designer的帮助文档里面充满了宝藏&#xff0c;最近就发现一个notesitem对象的SaveToDisk属性&#xff0c;你可以设置它为false&#xff0c;这样&#xff0c;虽然文档保存了&#xff0c;但这个字段本身可以不用保存&#xff0c;不仅可以…

ROS分布式演练,多台设备进行通信的配置

1、概述 前面我们做的操作都是在单个设备上进行&#xff0c;也就是分别开启多个终端&#xff0c;在不同终端上启动节点等相关操作&#xff0c;这里我们使用两台设备来控制&#xff0c;一台虚拟机和一台无人车(使用VNC Viewer连上去&#xff0c;也可以看做一台Linux虚拟机) VNC…

初识FFmpeg

前言 无意间见到群里的小伙伴展示视频工具。功能比较多&#xff0c;包括视频编码修改&#xff0c;画质处理&#xff0c;比例处理、名称提取&#xff0c;剪辑、标题拆解。因此开始了FFmpeg学习。以下摘自百度百科的解释。 FFmpeg是一套可以用来记录、转换数字音频、视频&#xf…

【React】02.create-react-app基础操作

文章目录 当前以及未来的开发&#xff0c;一定是&#xff1a;组件化开发如何划分组件React的工程化/组件化开发create-react-app基础运用运用react常用版本一个React项目中&#xff0c;默认会安装 2023年最新珠峰React全家桶【react基础-进阶-项目-源码-淘系-面试题】 当前以及…

c++ Vector 学习

vevtor 是c 中自带得动态数组&#xff0c;dynamic array array can hold different values/objects of same type 可以装不同得类型或者对象 dynamic size can be changed at runtime 可以运行得时候改变 要使用的话&#xff0c;先引入 #include <vector> std::vector…

稳定性测试—fastboot和monkey区别

一、什么是稳定性测试 稳定性测试是指检验程序在一定时间内能否稳定地运行&#xff0c;在不同的场景下能否正常地工作的过程。主要目的是检测崩溃、内存泄漏、堆栈错误等缺陷。 二、Monkey 1.什么是Monkey 是一个命令行工具&#xff0c;通常在adb安卓调试运行&#xff0c;模…

Bat批量处理

一&#xff1a;创建文件夹 excel创建文件 复制出来新建文本文件 另存为bat 双击bat 二&#xff1a;批量移动文件 A列&#xff1a;获取的文件名列表 dir /b/o:n> original.txt B列&#xff1a;填充序号 C列公式&#xff1a;每隔9行增加1 INT((ROW(B1)-1)/9)1 D列公式&am…