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

news2024/11/26 19:38:47

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 排查,再开一篇介绍

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CodeWhisperer 的使用心得

文章作者&#xff1a;小SS 亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术&#xff0c;观点&#xff0c;和项目&#xff0c;并将中国优秀开发者或技术推荐给全球云社…

第9章_子查询

文章目录 1 需求分析与问题解决1.1 实际问题1.2 子查询的基本使用1.3 子查询的分类1.3.1 分类方式11.3.2 分类方式2 1.4 演示代码 2 单行子查询2.1 单行比较操作符2.2 代码示例2.3 HAVING中的子查询2.4 CASE中的子查询2.5 子查询中的空值问题2.6 非法使用子查询演示代码 3 多行…

错误页 模板

下载链接&#xff1a;https://ext.dcloud.net.cn/plugin?id15229 http://下载链接&#xff1a;https://ext.dcloud.net.cn/plugin?id15229 如有问题可添加下方名片

Day39 QTableWidget类的使用

1.简介 介绍QtableWidget各种属性的用法&#xff0c;以及常用的一些信号&#xff0c;最后利用这些特性&#xff0c;制作一个用于下发设备运行参数的表格。该表格可以实现折叠和取消折叠&#xff0c;在源代码中用了事件过滤器实现&#xff0c;也可以用自带的click信号。显示了图…

我用 LangChain 打造自己的 LLM 应用项目

随着LLM的技术发展&#xff0c;其在业务上的应用越来越关键&#xff0c;通过LangChain大大降低了LLM应用开发的门槛。本文通过介绍LangChain是什么&#xff0c;LangChain的核心组件以及LangChain在实际场景下的使用方式&#xff0c;希望帮助大家能快速上手LLM应用的开发。 技术…

二叉树采用二叉链表存储:编写计算二叉树最大宽度的算法(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)

二叉树采用二叉链表存储&#xff1a;编写计算二叉树最大宽度的算法 &#xff08;二叉树的最大宽度是指二叉树所有层中结点个数的最大值&#xff09; 和二叉树有关的代码&#xff0c;基本都逃不过“先中后层”&#xff0c;这四种遍历 而我们这里是让你计算最大宽度&#xff0c…

tail:无法打开文件错误

错误 解决方法与原因 原因是因为之前启动的没有关闭 解决方法 1.输入ls 2.可以看到里面有start_all.sh和stop_all.sh(我们使用stop_all.sh关闭) 3.使用start_all.sh重新启动 4.我们再使用命令查看&#xff0c;可以看到没有错误了

「Verilog学习笔记」奇偶校验

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 通常所说的奇偶校验&#xff1a; 奇校验&#xff1a;对输入数据添加1位0或者1&#xff0c;使得添加后的数包含奇数个1&#xff1b; 比如100&#xff0c;有奇数个1&am…

汇总记录Python常用的基础内置方法

这里汇总记录一些Python常用的基础内置方法 (参照哔站有一个大佬"小飞有点东西"的笔记整理记录而得&#xff0c;仅限方便需要的时候可以直接在网上搜索查阅而整理记录) 输出/输入 print() input()print打印颜色设置 显示方式;前景颜色;背景颜色&#xff0c;这3个…

CRM系统的常用功能

CRM系统旨在帮助企业有效管理客户关系&#xff0c;提升销售和市场营销业绩&#xff0c;以及提供优质的客户服务。以下是CRM系统常见的功能和模块&#xff1a; 1. 客户信息管理&#xff1a; - 中央化存储客户信息&#xff1a;CRM系统允许企业集中管理和维护客户信息&#xff0c…

腾讯云3年/5年时长云服务器购买攻略分享

腾讯云是腾讯旗下云计算品牌&#xff0c;为了吸引用户经常推出各种优惠活动&#xff0c;最吸引用户的还是特惠云服务器&#xff0c;下面给大家分享腾讯云3年/5年时长特惠服务器购买入口及攻略&#xff01; 购买入口&#xff1a;传送门>>> 购买攻略&#xff1a; 进入…

算法通关村第六关-白银挑战树

大家好我是苏麟 , 今天聊聊树 . 大纲 树的概念二叉树满二叉树完全二叉树 树的性质树的定义与存储方式树的遍历 树的概念 树是我们计算机中非常重要的一种数据结构&#xff0c;同时使用树这种数据结构&#xff0c;可以描述现实生活中的很多事物&#xff0c;例如家谱、单位的组织…

01-单节点部署clickhouse及简单使用

1、下载rpm安装包&#xff1a; 官网&#xff1a;https://packages.clickhouse.com/rpm/stable/ clickhouse19.4版本之后只需下载3个rpm安装包&#xff0c;上传到节点目录即可 2、rpm包安装&#xff1a; 安装顺序为conmon->server->client 执行 rpm -ivh ./clickhouse-…

第二十五章 BEV感知系列二(车道线感知)

前言 近期参与到了手写AI的车道线检测的学习中去&#xff0c;以此系列笔记记录学习与思考的全过程。车道线检测系列会持续更新&#xff0c;力求完整精炼&#xff0c;引人启示。所需前期知识&#xff0c;可以结合手写AI进行系统的学习。 BEV感知系列是对论文Delving into the De…

proxifier 2023年11月最新版的安装

前言 Proxifier 是一款功能非常强大的socks5客户端&#xff0c;可以让不支持通过代理服务器工作的网络程序能通过HTTPS或SOCKS代理或代理链。支持64位系统支持Xp&#xff0c;Vista&#xff0c;Win7&#xff0c;支持socks4&#xff0c;socks5&#xff0c;http 代理协议&#xf…

python 深度学习 解决遇到的报错问题8

本篇继python 深度学习 解决遇到的报错问题7-CSDN博客 目录 一、OSError: [WinError 127] 找不到指定的程序。 Error loading "D:\my_ruanjian\conda-myenvs\deeplearning\lib\site-packages\torch\lib\caffe2_detectron_ops.dll" or one of its dependencies. 二、…

婚庆策划小程序制作教程

本文将向你展示如何使用小程序制作平台&#xff0c;轻松制作婚庆策划小程序。只需按照以下步骤操作&#xff0c;你就能拥有自己的专业级婚庆策划小程序。 登录小程序制作平台 首先&#xff0c;你需要登录小程序制作平台。在浏览器搜索乔拓云&#xff0c;然后使用你的账号登录。…

【复盘】记录一次JVM 异常问题 java.lang.OutOfMemoryError: unable to create new native thread

背景是最新运营提了一个需求&#xff0c;需要根据用户信息拉去三分机构的信贷数据&#xff0c;需要达到一天百万级别&#xff0c;但是经过实际测试&#xff0c;也只能达到40W量级&#xff0c;具体就是通过起多个Spring Boot项目&#xff0c;每个项目1S拉一个用户&#xff0c;基…

Docker网络模式_Docker常用命令_以及Docker如何给运行的镜像内容连接互联网_Docker网络模式原理---Docker工作笔记004

然后我们来看一下docker的网络模式: 这个docker我们先看一下电脑上的网络,有两个,1个是lo是测试用的一个是enp0s3这个是我们以太网地址,然后我们去: 安装docker 安装后我们再去ip address可以看到多出来一个网络是docker0 这里ip地址是172.17.0.1这个是私有地址外部无法访问 这…

软件测试必备技能—接口测试

接口测试&#xff0c;其实并没有那么可怕&#xff0c;但是作为测试人员也是必不可少的技能。 接口分为&#xff1a;内部接口和外部接口。 内部接口&#xff1a;是浏览器与服务器的接口。这个很容易理解&#xff0c;web开发一般分前端和后端&#xff0c;前端开发人员用html/cs…