精华内容
下载资源
问答
  • JVM内存dump分析工具MAT独立安装包,分析内存溢出利器,可以准确定位内存异常原因,解决问题,MemoryAnalyzer-1.10.0.20200225.zip
  • jvm内存分析工具mat

    2019-09-20 23:53:57
    mat用于分析JVM的内存dump信息,是在JVM内存异常时进行内存分析的好工具
  • 内存分析工具MAT

    2018-01-09 18:16:19
    Android内存分析工具,和AS的.hprof文件配合使用分析应用APP的内存。
  • Mac OS java内存分析工具,Eclipse MAT(Memory analyse tool)
  • 内存分析工具MAT使用

    2017-02-08 09:43:31
    图文并茂,具体实例的形式说明内存泄露分析工具MAT的具体使用方法
  • 《JVM 内存分析工具 MAT 的深度讲解与实践——入门篇》介绍 MAT 产品功能、基础概念、与其他工具对比、Quick Start 指南。 《JVM 内存分析工具 MAT 的深度讲解与实践——进阶篇》展开并详细介绍 .

    本文转载自:  https://mp.weixin.qq.com/s/6_9GRSaUm-6qePP0OBdclg

    JVM 内存分析往往由团队较资深同学来做,本系列帮助读者全面深度掌握 MAT 的使用方法。即使没有分析实践经验,也能快速成为内存分析高手!

    本系列共计3篇:

    1. 《JVM 内存分析工具 MAT 的深度讲解与实践——入门篇》介绍 MAT 产品功能、基础概念、与其他工具对比、Quick Start 指南。

    2. JVM 内存分析工具 MAT 的深度讲解与实践——进阶篇展开并详细介绍 MAT 的核心功能,并在具体实战场景下讲解帮大家加深体会。

    3. JVM 内存分析工具 MAT 的深度讲解与实践——高阶篇总结复杂内存问题的系统性分析方法,并通过一个综合案例提升大家的实战能力。


     

    一、MAT 工具简介

    MAT(全名:Memory Analyzer Tool),是一款快速便捷且功能强大丰富的 JVM 堆内存离线分析工具。其通过展现 JVM 异常时所记录的运行时堆转储快照(Heap dump)状态(正常运行时也可以做堆转储分析),帮助定位内存泄漏问题或优化大内存消耗逻辑。

     

    1.1  MAT 使用场景及主要解决问题

    • 内存溢出,JVM堆区或方法区放不下存活及待申请的对象。如:高峰期系统出现 OOM(Out of Memory)异常,需定位内存瓶颈点来指导优化。

    • 内存泄漏,不会再使用的对象无法被垃圾回收器回收。如:系统运行一段时间后出现 Full GC,甚至周期性 OOM 后需人工重启解决。

    • 内存占用高。如:系统频繁 GC ,需定位影响服务实时性、稳定性、吞吐能力的原因。

     

    1.2  基础概念

    Heap Dump:Java 进程堆内内存在一个时间点的快照,支持 HPROF 及 DTFJ 格式,前者由 Oracle 系列 JVM 生成,后者是 IBM 系列 JVM 生成。其内容主要包含以下几类:

    • 对象实例信息:对象所属类名、基础类型和引用类型的属性等。

    • 所有类信息:类加载器、类名、继承关系、静态属性等。

    • GC Root:GC Root 代表通过可达性分析来判定 JVM 对象是否存活的起始集合。JVM 采用追踪式垃圾回收(Tracing GC)模式,从所有 GC Roots 出发通过引用关系可以关联的对象就是存活的(所以不可回收),其余的不可达的对象(Unreachable object:如果无法从 GC Root 找到一条引用路径能到达某对象,则该对象为Unreachable object)可以回收。一般是未执行完的线程自身,或运行线程的调用栈上的对象(如局部变量、方法参数)、System class loader 加载的类、native code 保留的活动对象等。

    • 线程栈及局部变量:快照生成时刻的所有线程的线程栈帧,以及每个线程栈的局部变量。

    Shallow Heap:代表一个对象结构自身的大小,不包括其属性引用对象所占的内存。如 java.util.ArrayList 对象的 Shallow Heap 包含8字节的对象头、8字节的对象数组属性 elementData 引用 、 4字节的 size 属性、4字节的 modCount 属性(从 AbstractList 继承及对象头占用内存大小),有的对象可能需要加对齐填充但 ArrayList 自身已对齐不需补充,注意不包含 elementData 具体数据占用的内存大小。

    Retained Set:一个对象的 Retained Set,指的是该对象被 GC 回收后,所有能被回收的对象集合(如下图所示,G的 Retain Set 只有 G 并不包含 H,原因是虽然 H 也被 G 引用,但由于 H 也被 F 引用 ,G 被垃圾回收时无法释放 H);另外,当该对象无法被 GC 回收,则其 Retained set 也必然无法被 GC 回收。

    Retained Heap:一个对象被 GC 回收后,可释放的内存大小,等于释放对象的 Retained Heap 中所有对象的 Shallow Heap 的和(如下图所示,E 的 Retain Heap 就是 G 与 E 的 Shallow Heap 总和,同理不包含 H)。

    Dominator tree:如果所有指向对象 Y 的路径都经过对象 X,则 X 支配(dominate) Y(如下图中,C、D 均支配 F,但 G 并不支配 H)。Dominator tree 是根据对象引用及支配关系生成的整体树状图,支配树清晰描述了对象间的依赖关系,下图左的 Dominator tree 如下图右下方支配树示意图所示。支配关系还有如下关系:

    • Dominator tree 中任一节点的子树就是被该节点支配的节点集合,也就是其 Retain Set

    • 如果 X 直接支配 Y,则 X 的所有支配节点均支配 Y。

    图片

    OQL:类似于 SQL 的 MAT 专用统一查询语言,可以根据复杂的查询条件对 dump 文件中的类或者对象等数据进行查询筛选。

    Outgoing references、incoming references:直击对象间依赖关系,MAT 也提供了链式快速操作。

    • outgoing references:对象引用的外部对象(注意不包含对象的基本类型属性。基本属性内容可在 inspector 查看)。

    • incoming references:直接引用了当前对象的对象,每个对象的 incoming references 可能有 0 到多个。

     

    二、MAT 功能概述及对比

    2.1  MAT 功能概述

    注:MAT 的产品能力非常丰富,本文简要总结产品特性全貌,下一篇文章《JVM 内存分析实战进阶篇——核心功能及应用场景》,会详细介绍各项核心功能的场景、案例、最佳实践等。

    MAT 的工作原理

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

     

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

    类别一、内存分布

    • 全局概览信息:堆内存大小、对象个数、类的个数、类加载器的个数、GC root 个数、线程概况等全局统计信息。

    • Histogram:罗列每个类实例的内存占比,包括自身内存占用量(Shallow Heap)及支配对象的内存占用量(Retain Heap),支持按 package、class loader、super class、class 聚类统计,最常用的功能之一。

    • Dominator tree:按对象的 Retain Heap 排序,也支持按多个维度聚类统计,最常用的功能之一。

    • Leak Suspects:直击引用链条上占用内存较多的可疑对象,可解决一些基础问题,但复杂的问题往往帮助有限。

    • Top Consumers:展现哪些类、哪些 class loader、哪些 package 占用最高比例的内存。

    类别二、对象间依赖

    • References:提供对象的外部引用关系、被引用关系。通过任一对象的直接引用及间接引用详情(主要是属性值及内存占用),进而提供完善的依赖链路详情。

    • Dominator tree:支持按对象的 Retain Heap 排序,并提供详细的支配关系,结合 references 可以实现大对象快速关联分析;

    • Thread overview:展现转储 dump 文件时线程栈帧等详细状态,也提供各线程的 Retain Heap 等关联内存信息。

    • Path To GC Roots:提供任一对象到 GC Root 的链路详情,帮助了解不能被 GC 回收的原因。

    类别三、对象状态

    • 最核心的是通过 inspector 面板提供对象的属性信息、类继承关系信息等数据,协助分析内存占用高与业务逻辑的关系

    • 集合状态的检测,如:通过 ArrayList 或数组的填充率定位空集合空数组造成的内存浪费、通过 HashMap 冲突率判定 hash 策略是否合理等。

    类别四、条件检索

    • 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)

    • 内存分布及对象间依赖的众多功能,均支持按字符串检索、按正则检索等操作。

    • 按虚拟内存地址寻址,根据对象的十六进制地址查找对象。

    以上是 MAT 最核心的功能,为了便于记忆与回顾,整理了如下脑图,其中红色框标红的内容是最最常用的功能,熟练掌握基本可以 Cover 80%以上的离线堆内内存分析问题。

     

     

    2.2  常见内存分析工具对比

    注:下图中 Y 表示支持,N 表示不支持,时间截至发稿前。

    产品功能

    MAT

    JProfiler

    Visual VM

    jhat

    jmap

    hprof

    对象间关联、深浅堆、GC Root、支配树、线程分析YNNNNN
    离线分析YNYY

    N

    N
    内存实时分配情况NYYYYY
    OQLYNYNNN
    内存分配堆栈、热点NYNNNN
    堆外内存分析NNNNNN

    注 1:Dump 文件包含快照被转储时刻的 Java 对象 在堆内存中的分布情况,但快照只是瞬间的记录,所以不包含对象在何时、在哪个方法中被分配这类信息

    注 2:一般堆外内存溢出排查可结合 gperftools 与 btrace 排查,此类文章较多不展开介绍。

     

    三、Quick Start 及使用技巧

    3.1  Quick Start

    1. 安装 MAT:【下载链接: https://www.eclipse.org/mat/downloads.php】,也可集成在 Eclipse 中(路径:Eclipse → Help → Eclipse Marketplace → 搜 “MAT”)。

    2. 调节 MAT 堆内存大小:MAT 分析时也作为 Java 进程运行,建议至少分配 dump 文件大小的1.2倍内存给 MAT 保证分析速度会。方式是修改 MemoryAnalyer.ini 文件,调整 Xmx 参数(Windows 可用搜索神器 everything 软件查找并修改、MAC OS 一般在 /Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini,如找不到可用 Alfred 软件查询修改)。

    3. 获取堆快照 dump 文件(堆转储需要先执行 Full GC,线上服务使用时请注意影响),一般用三种方式:

    • 使用 JDK 提供的 jmap 工具,命令是 jmap -dump:format=b,file=<dumpfile> <pid>。当进程接近僵死时,可以添加 -F 参数强制转储:jmap -F -dump:format=b,file=<dumpfile> <pid>。

    • 本地运行的 Java 进程,直接在 MAT 使用 File → accquire heap dump 功能获取。

    • 启动 Java 进程时配置JVM参数:-XX:-HeapDumpOnOutOfMemoryError,当发生 OOM 时无需人工干预会自动生成 dump文件。指定目录用 -XX:HeapDumpPath=<filepath> 来设置。

    4. 分析 dump 文件建立索引:路径是 File → Open Heap Dump ,然后 MAT 会建立索引并分析,dump 文件较大时耗时会很长。分析后 dump 文件所在目录会有后缀为 index 的索引文件,也会有包含 HTML 格式的后缀为 zip 的文件。

    5. MAT 呈现概要视图(Overview),包含三个部分:

    • 全局概览信息,堆内存大小、类数量、实例数量、Class Loader数量。

    • Unreachable Object Histogram,展现转储快照时可被回收的对象信息(一般不需要关注,除非 GC 频繁影响实时性的场景分析才用到)

    • Biggest Objects by Retained Size,展现经过统计过的哪几个实例所关联的对象占内存总和较高,以及具体占用的内存大小,一般相关代码比较简单情况下,往往可以直接分析具体的引用关系异常,如内存泄漏等。此外也包含了最大对象和链接支持继续深入分析。

    6. 继续使用 MAT 各种工具。如果代码比较复杂,需要继续使用 MAT 各种工具并结合业务代码进一步分析内存异常的原因。最常用的几项如下(具体案例、场景、使用方式在《JVM 内存分析工具 MAT 的深度讲解与实践——进阶篇》详细介绍):

    • 查看堆整体情况的:Histogram、Dominator tree、Thread details等(各项功能入口如下)。

    • MAT 分析过的 Top Consumers 、Leak Suspects等。

    • 对象级别分析的 Path to GC Root、incoming references、outgoing references 等。

     

    3.2  使用技巧及注意事项

    一、注意对运行进程的性能影响。Heap dump 时会先进行 Full GC,另外为保证对象数据视图一致,需要在安全点 Stop The World 暂停响应,线上服务进行务必注意性能影响。可以采取以下技巧减少影响:

    • 先禁用入口流量,再执行 dump 动作。

    • 选择影响较小时 dump 内存。

    • 使用脚本捕获指定事件时 dump 内存。

    二、大文件分析方法及注意事项。

    • 大文件分析方法:开发机配置不足无法分析,可在服务器先执行分析后,基于分析后的索引文件直接查看结果,一般 dump 文件不高于分析机主存 1.2 倍可直接在开发机分析;若 dump 文件过大,可以使用 MAT 提供的脚本在配置高的高配机器先建立索引再直接展现索引分析结果(一般是 Linux 机器,可以使用 MAT 提供的脚本:./ParseHeapDump.sh $HEAPDUMP,堆信息有 unreachable 标记的垃圾对象,在 dump 时也保存了下来,默认不分析此部分数据,如需要在启动脚本 ParseHeapDump.sh 中加入:-keep_unreachable_objects)。

    • 如果不关注堆中不可达对象,使用“live”参数可以减小文件大小,命令是 jmap -dump:live,format=b,file=<dumpfile> <pid>

    • Dump 前主动手动执行一次 FULL GC ,去除无效对象进一步减少 dump 堆转储及建立索引的时间。

    • Dump文件巨大,建立索引后发现主视图中对象占用内存均较小,这是因为绝大部分对象未被 GC Roots 引用可释放。 

    • Dump 时注意指定到空间较大的磁盘位置,避免打满分区影响服务。

    • 建立 dump 索引机器的磁盘空间需要足够大,一般至少是 dump 文件的两倍,因为生成的中间索引文件也较大,如下图:

    图片

    三、其他:

    • JDK 版本问题:如遇“VMVersionMismatchException”,使用启动目标进程的 JDK 版本即可。

    • 部分核心功能主界面未展现,问题足够复杂时需打开,如 MAT 默认不打开 inspector,如需根据对象数据值做业务分析,建议打开该视图。

    • 配置了 HeapDumpOnOutOfMemoryError 参数,但 OutOfMemoryError 时但没有自动生成 dump 文件,可能原因有三个:

      • 应用程序自行创建并抛出 OutOfMemoryError

      • 进程的其他资源(如线程)已用尽

      • C 代码(如 JVM 源码)中堆耗尽,这种可能由于不同的原因而出现,例如在交换空间不足的情况下,进程限制用尽或仅地址空间的限制,此时 dump 文件分析并无实质性帮助。

     

    至此本文讲解了 MAT 实践必备的初级内容,在下一篇《JVM 内存分析工具 MAT 的深度讲解与实践——进阶篇》会展开并详细介绍 MAT 丰富的核心功能,每个功能点讲解都会从具体场景聊起,帮助大家在实战场景下加深体会实现进阶。

     

    参考内容

    MAT官网:https://help.eclipse.org/2020-09/index.jsp

    展开全文
  • 在spark streaming程序持续运行中,经过一段时间之后,executor频繁发生GC time,导致每个批次处理时间变长,推测程序存在内存泄漏,因此引入MAT内存分析工具 MAT的安装 由于我们已经习惯了IDEA开发,为了MAT下载个...

    这里写自定义目录标题

    背景

    在spark streaming程序持续运行中,经过一段时间之后,executor频繁发生GC time,导致每个批次处理时间变长,推测程序存在内存泄漏,因此引入MAT内存分析工具

    MAT的安装

    由于我们已经习惯了IDEA开发,为了MAT下载个Eclispse不值得,所以我们安装一个独立版的MAT。

    MAT下载地址:https://www.eclipse.org/mat/downloads.php
    选择自己的操作系统进行下载,本文以 Mac OSX (Mac/Cocoa/x86_64) 系统为例。
    下载得到一个zip文件,解压后得到mat文件,直接双击mat文件会出现异常,此时的解决办法:
    打开终端进入到mat目录:

    cd ~/Downloads/mat.app/Contents/MacOS/
    ./MemoryAnalyzer -data ./dump

    启动成功,打开页面,安装成功!~
    在这里插入图片描述

    解决问题

    1. 利用jmap指令 ,生成内存快照文件,PID指的是进程ID

    jmap -dump:format=b,file=文件名 PID

    1. 打开MAT,选择 Open a Head Dump ,指定到内存快照文件,期间选择 Leak Suspects Report
      在这里插入图片描述

    2. 稍等片刻会自动生成内存分析结果,可以看到最大的问题是JDBC4Connection存在未释放的内存

    3. Histogram查询,点击Actions下的Histogram项得到结果:
      在这里插入图片描述
      Shallow Heap浅堆:java对象占用的内存
      Retained Heap深堆:java对象及对象引用的类占用的内存 ,jvm gc回收时释放的内存
      Retained Heap深堆大于等于Shallow Heap浅堆

      我们分析的目标是Retained Heap,选择 Merge Shortest Paths to GC Roots -> exclude all phantom/weak/soft etc.references ,然后一层一层的往下点,可以看到内存没有释放的原因了;通过 outGoing references 也可以查看该实例中引用了那些对象一直没有释放,最后定位到代码的问题。

    在这里插入图片描述
    在这里插入图片描述

    MAT工具的使用远远不止这些,其他的用法以后用到了再说明

    参考资料:
    https://blog.csdn.net/mahl1990/article/details/79298616
    https://blog.csdn.net/mynamepg/article/details/81560917
    https://www.cnblogs.com/aaa2832/p/3594749.html

    展开全文
  • 可以可视化分析内存情况,直观的看到数据,方便的锁定问题所在位置。
  • 本文详细讲解 MAT 众多内存分析工具功能,这些功能组合使用异常强大,熟练使用几乎可以解决所有的堆内存离线分析的问题。我们将功能划分为4类:内存分布详情、对象间依赖、对象状态详情、按条件检索。每大类有多个...

    1. 前言

    本文详细讲解 MAT 众多内存分析工具功能,这些功能组合使用异常强大,熟练使用几乎可以解决所有的堆内存离线分析的问题。我们将功能划分为4类:内存分布详情、对象间依赖、对象状态详情、按条件检索。每大类有多个功能点,本文会逐一讲解各功能的场景及用法。此外,添加了原创或引用案例加强理解和掌握。
    注:在该系列开篇文章《JVM 内存分析工具 MAT 的深度讲解与实践——入门篇》中介绍了 MAT 的使用场景及安装方法,不熟悉 MAT 的读者建议先阅读上文并安装,本文案例很容易在本地实践。另外,上文中产品介绍部分顺序也对应本文功能讲解的组织,如下图:
    在这里插入图片描述
    为减少对眼花缭乱的菜单的迷茫,可以通过下图先整体熟悉下各功能使用入口,后续都会讲到
    在这里插入图片描述

    2. 内存分布详解及实战

    2.1 全局信息概览

    功能:展现堆内存大小、对象数量、class 数量、class loader 数量、GC Root 数量、环境变量、线程概况等全局统计信息。
    使用入口:MAT 主界面 → Heap Dump Overview
    举例:下面是对象数量、class loader 数量、GC Root 数量,可以看出 class loader 存在异常
    在这里插入图片描述
    举例:下图是线程概况,可以查看每个线程名、线程的 Retained Heap、daemon 属性等
    在这里插入图片描述
    使用场景 全局概览呈现全局统计信息,重点查看整体是否有异常数据,所以有效信息有限,下面几种场景有一定帮助:

    • 方法区溢出时(Java 8后不使用方法区,对应堆溢出),查看 class 数量异常多,可以考虑是否为动态代理类异常载入过多或类被反复重复加载。
    • 方法区溢出时,查看 class loader 数量过多,可以考虑是否为自定义 class loader 被异常循环使用。
    • GC Root 过多,可以查看 GC Root 分布,理论上这种情况极少会遇到,笔者只在 JNI 使用一个存在 BUG 的库时遇到过。
    • 线程数过多,一般是频繁创建线程但无法执行结束,从概览可以了解异常表象,具体原因可以参考本文线程分析部分内容,此处不展开。

    2.2 Dominator tree

    注:笔者使用频率的 Top1,是高效分析 Dump 必看的功能。

    功能

    展现对象的支配关系图,并给出对象支配内存的大小(支配内存等同于 Retained Heap,即其被 GC 回收可释放的内存大小)
    支持排序、支持按 package、class loader、super class、class 聚类统计

    使用入口:全局支配树: MAT 主界面 → Dominator tree。
    举例: 下图中通过查看 Dominator tree,了解到内存主要是由 ThreadAndListHolder-thread 及 main 两个线程支配(后面第2.6节会给出整体案例)。
    在这里插入图片描述
    使用场景

    • 开始 Dump 分析时,首先应使用 Dominator tree 了解各支配树起点对象所支配内存的大小,进而了解哪几个起点对象是 GC 无法释放大内存的原因。

    • 当个别对象支配树的 Retained Heap 很大存在明显倾斜时,可以重点分析占比高的对象支配关系,展开子树进一步定位到问题根因,如下图中可看出最终是 SameContentWrapperContainer 对象持有的 ArrayList 过大
      在这里插入图片描述

    • 在 Dominator tree 中展开树状图,可以查看支配关系路径(与 outgoing reference 的区别是:如果 X 支配 Y,则 X 释放后 Y必然可释放;如果仅仅是 X 引用 Y,可能仍有其他对象引用 Y,X 释放后 Y 仍不能释放,所以 Dominator tree 去除了 incoming reference 中大量的冗余信息

    • 有些情况下可能并没有支配起点对象的 Retained Heap 占用很大内存(比如 class X 有100个对象,每个对象的 Retained Heap 是10M,则 class X 所有对象实际支配的内存是 1G,但可能 Dominator tree 的前20个都是其他class 的对象),这时可以按 class、package、class loader 做聚合,进而定位目标。
      例如:
      下图中各 GC Roots 所支配的内存均不大,这时需要聚合定位爆发点。
      在这里插入图片描述
      在 Dominator tree 展现后按 class 聚合,如下图
      在这里插入图片描述
      可以定位到是 SomeEntry 对象支配内存较多,然后结合代码进一步分析具体原因
      在这里插入图片描述

    • 在一些操作后定位到异常持有 Retained Heap 对象后(如从代码看对象应该被回收),可以获取对象的直接支配者,操作方式如下
      在这里插入图片描述

    2.3 Histogram 直方图

    注:笔者使用频率 Top2

    功能

    • 罗列每个类实例的数量、类实例累计内存占比,包括自身内存占用量(Shallow Heap)及支配对象的内存占用量(Retain Heap)。
    • 支持按对象数量、Retained Heap、Shallow Heap(默认排序)等指标排序;支持按正则过滤;支持按 package、class loader、super class、class 聚类统计,

    使用入口:MAT 主界面 → Histogram;注意 Histogram 默认不展现 Retained Heap,可以使用计算器图标计算,如下图所示。
    在这里插入图片描述
    使用场景

    • 有些情况 Dominator tree 无法展现出热点对象(上文提到 Dominator tree 支配内存排名前20的占比均不高,或者按 class 聚合也无明显热点对象,此时 Dominator tree 很难做关联分析判断哪类对象占比高),这时可以使用 Histogram 查看所有对象所属类的分布,快速定位占据 Retained Heap 大头的类。
    • 使用技巧
      1). Integer,String 和 Object[] 一般不直接导致内存问题。为更好的组织视图,可以通过 class loader 或 package 分组进一步聚焦,如下图。
      在这里插入图片描述
      2). Histogram 支持使用正则表达式来过滤。例如,我们可以只展示那些匹配com.q.*的类。
      在这里插入图片描述
      3). 可以在 Histogram 的某个类继续使用 outgoing reference 查看对象分布,进而定位哪些对象是大头
      在这里插入图片描述在这里插入图片描述

    2.4 Leak Suspects

    功能:具备自动检测内存泄漏功能,罗列可能存在内存泄漏的问题点。
    使用入口:一般当存在明显的内存泄漏时,分析完Dump文件后就会展现,也可以如下图在 MAT 主页 → Leak Suspects。
    使用场景:需要查看引用链条上占用内存较多的可疑对象。这个功能可解决一些基础问题,但复杂的问题往往帮助有限。
    举例

    • 下图中 Leak Suspects 视图展现了两个线程支配了绝大部分内存。
      在这里插入图片描述
    • 下图是点击上图中 Keywords 中 “Details” ,获取实例到 GC Root 的最短路径、dominator 路径的细信息。
      在这里插入图片描述

    2.5 Top Consumers

    • 功能:最大对象报告,可以展现哪些类、哪些 class loader、哪些 package 占用最高比例的内存,其功能 Histogram 及 Dominator tree 也都支持。
    • 使用场景:应用程序发生内存泄漏时,查看哪些泄漏的对象通常在 Dump 快照中会占很大的比重。因此,对简单的问题具有较高的价值。

    2.6 综合案例一

    使用工具项:Heap dump overview、Dominator tree、Histogram、Class Loader Explorer(见3.4节)、incoming references(见3.1节)

    程序代码

    package com.q.mat;
    import java.util.*;
    import org.objectweb.asm.*;
    
    public class ClassLoaderOOMOps extends ClassLoader implements Opcodes {
    
        public static void main(final String args[]) throws Exception {
            new ThreadAndListHolder(); // ThreadAndListHolder 类中会加载大对象
    
            List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
            final String className = "ClassLoaderOOMExample";
            final byte[] code = geneDynamicClassBytes(className);
    
            // 循环创建自定义 class loader,并加载 ClassLoaderOOMExample
            while (true) {
                ClassLoaderOOMOps loader = new ClassLoaderOOMOps();
                Class<?> exampleClass = loader.defineClass(className, code, 0, code.length); //将二进制流加载到内存中
                classLoaders.add(loader);
                // exampleClass.getMethods()[0].invoke(null, new Object[]{null});  // 执行自动加载类的方法,通过反射调用main
            }
        }
    
        private static byte[] geneDynamicClassBytes(String className) throws Exception {
            ClassWriter cw = new ClassWriter(0);
            cw.visit(V1_1, ACC_PUBLIC, className, null, "java/lang/Object", null);
    
            //生成默认构造方法
            MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    
            //生成构造方法的字节码指令
            mw.visitVarInsn(ALOAD, 0);
            mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mw.visitInsn(RETURN);
            mw.visitMaxs(1, 1);
            mw.visitEnd();
    
            //生成main方法
            mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
            //生成main方法中的字节码指令
            mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
    
            mw.visitLdcInsn("Hello world!");
            mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mw.visitInsn(RETURN);
            mw.visitMaxs(2, 2);
            mw.visitEnd();  //字节码生成完成
    
            return cw.toByteArray();  // 获取生成的class文件对应的二进制流
    
        }
    }
    
    package com.q.mat;
    
    import java.util.*;
    import org.objectweb.asm.*;
    
    public class ThreadAndListHolder extends ClassLoader implements Opcodes {
        private static Thread innerThread1;
        private static Thread innerThread2;
        private static final SameContentWrapperContainerProxy sameContentWrapperContainerProxy = new SameContentWrapperContainerProxy();
    
        static {
            // 启用两个线程作为 GC Roots
            innerThread1 = new Thread(new Runnable() {
                public void run() {
                    SameContentWrapperContainerProxy proxy = sameContentWrapperContainerProxy;
                    try {
                        Thread.sleep(60 * 60 * 1000);
                    } catch (Exception e) {
                        System.exit(1);
                    }
                }
            });
            innerThread1.setName("ThreadAndListHolder-thread-1");
            innerThread1.start();
    
            innerThread2 = new Thread(new Runnable() {
                public void run() {
                    SameContentWrapperContainerProxy proxy = proxy = sameContentWrapperContainerProxy;
                    try {
                        Thread.sleep(60 * 60 * 1000);
                    } catch (Exception e) {
                        System.exit(1);
                    }
                }
            });
            innerThread2.setName("ThreadAndListHolder-thread-2");
            innerThread2.start();
        }
    }
    
    class IntArrayListWrapper {
        private ArrayList<Integer> list;
        private String name;
    
        public IntArrayListWrapper(ArrayList<Integer> list, String name) {
            this.list = list;
            this.name = name;
        }
    }
    
    class SameContentWrapperContainer {
        // 2个Wrapper内部指向同一个 ArrayList,方便学习 Dominator tree
        IntArrayListWrapper intArrayListWrapper1;
        IntArrayListWrapper intArrayListWrapper2;
    
        public void init() {
            // 线程直接支配 arrayList,两个 IntArrayListWrapper 均不支配 arrayList,只能线程运行完回收
            ArrayList<Integer> arrayList = generateSeqIntList(10 * 1000 * 1000, 0);
            intArrayListWrapper1 = new IntArrayListWrapper(arrayList, "IntArrayListWrapper-1");
            intArrayListWrapper2 = new IntArrayListWrapper(arrayList, "IntArrayListWrapper-2");
        }
    
        private static ArrayList<Integer> generateSeqIntList(int size, int startValue) {
            ArrayList<Integer> list = new ArrayList<Integer>(size);
            for (int i = startValue; i < startValue + size; i++) {
                list.add(i);
            }
            return list;
        }
    }
    
    class SameContentWrapperContainerProxy {
        SameContentWrapperContainer sameContentWrapperContainer;
    
        public SameContentWrapperContainerProxy() {
            SameContentWrapperContainer container = new SameContentWrapperContainer();
            container.init();
            sameContentWrapperContainer = container;
        }
    }
    
    
    启动参数:-Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/gjd/Desktop/dump/heapdump.hprof 
    -XX:-UseCompressedClassPointers -XX:-UseCompressedOops
    

    在这里插入图片描述
    分析过程
    1 . 首先进入 Dominator tree,可以看出是 SameContentWrapperContainerProxy 对象与 main 线程两者持有99%内存不能释放导致 OOM。
    在这里插入图片描述在这里插入图片描述
    2. 先来看方向一,在 Heap Dump Overview 中可以快速定位到 Number of class loaders 数达50万以上,这种基本属于异常情况,如下图所示。
    在这里插入图片描述
    3.使用 Class Loader Explorer 分析工具,此时会展现类加载详情,可以看到有524061个 class loader。我们的案例中仅有ClassLoaderOOMOps 这样的自定义类加载器,所以很快可以定位到问题
    在这里插入图片描述
    在这里插入图片描述
    4.如果类加载器较多,不能确定是哪个引发问题,则可以将所有的 class loader对象按类做聚类,如下图所示。
    在这里插入图片描述
    5.Histogram 会根据 class 聚合,并展现对象数量级其 Shallow Heap 及 Retained Heap(如Retained Heap项目为空,可以点击下图中计算机的图标并计算 Retained Heap),可以看到 ClassLoaderOOMOps 有524044个对象,其 Retain Heap 占据了370M以上(上述代码是100M左右
    在这里插入图片描述
    6.使用 incoming references,可以找到创建的代码位置
    在这里插入图片描述
    7.再来看方向二,同样在占据319M内存的 Obejct 数组采用 incoming references 查看引用路径,也很容易定位到具体代码位置。并且从下图中我们看出,Dominator tree 的起点并不一定是 GC根,且通过 Dominator tree 可能无法获取到最开始的创建路径,但 incoming references 是可以的
    在这里插入图片描述

    3. 对象间依赖详解及实战

    3.1 References

    注:笔者使用频率 Top2

    功能:在对象引用图中查看某个特定对象的所有引用关系(提供对象对其他对象或基本类型的引用关系,以及被外部其他对象的引用关系)。通过任一对象的直接引用及间接引用详情(主要是属性值及内存占用),提供完善的依赖链路详情。
    使用入口:目标域右键 → List objects → with outgoing references/with incoming references.
    使用场景

    • outgoing reference:查看对象所引用的对象,并支持链式传递操作。如查看一个大对象持有哪些内容,当一个复杂对象的 Retained Heap 较大时,通过 outgoing reference 可以查看由哪个属性引发。下图中 A 支配 F,且 F 占据大量内存,但优化时 F 的直接支配对象 A 无法修改。可通过 outgoing reference 看关系链上 D、B、E、C,并结合业务逻辑优化中间环节,这依托 dominator tree 是做不到的。
    • incoming reference:查看对象被哪些对象引用,并支持链式传递操作。如查看一个大对象都被哪些对象引用,下图中 K 占内存大,所以 J 的 Retained Heap 较大,目标是从 GC Roots 摘除 J 引用,但在 Dominator tree 上 J 是树根,无法获取其被引用路径,可通过 incoming reference 查看关系链上的 H、X、Y ,并结合业务逻辑将 J 从 GC Root 链摘除
      在这里插入图片描述

    3.2 Thread overview

    功能:展现转储 dump 文件时线程执行栈、线程栈引用的对象等详细状态,也提供各线程的 Retained Heap 等关联内存信息。
    使用入口:MAT 主页 → Thread overview
    使用场景

    • 查看不同线程持有的内存占比,定位高内存消耗线程(开发技巧:不要直接使用 Thread 或 Executor 默认线程名避免全部混合在一起,使用线程尽量自命名方便识别,如下图中 ThreadAndListHolder-thread 是自定义线程名,可以很容易定位到具体代码)
    • 查看线程的执行栈及变量,结合业务代码了解线程阻塞在什么地方,以及无法继续运行释放内存,如下图中 ThreadAndListHolder-thread 阻塞在 sleep 方法
      在这里插入图片描述

    3.3 Path To GC Roots

    功能:提供任一对象到 GC Root 的路径详情。
    使用入口:目标域右键 → Path To GC Roots
    使用场景:有时你确信已经处理了大的对象集合但依然无法回收,该功能能快速定位异常对象不能被 GC 回收的原因,直击异常对象到 GC Root 的引用路径。比 incoming reference 的优势是屏蔽掉很多不需关注的引用关系,比 Dominator tree 的优势是可以得到更全面的信息。

    小技巧:在排查内存泄漏时,建议选择 exclude all phantom/weak/soft etc.references 排除虚引用/弱引用/软引用等的引用链,因为被虚引用/弱引用/软引用的对象可以直接被 GC 给回收,聚焦在对象否还存在 Strong
    引用链即可。

    在这里插入图片描述

    3.4 class loader 分析

    功能

    • 查看堆中所有 class loader 的使用情况(入口:MAT 主页菜单蓝色桶图标 → Java Basics → Class Loader Explorer)。
    • 查看堆中被不同class loader 重复加载的类(入口:MAT 主页菜单蓝色桶图标 → Java Basics → Duplicated Classes)。

    使用场景

    • 当从 Heap dump overview 了解到系统中 class loader 过多,导致占用内存异常时进入更细致的分析定位根因时使用。
    • 解决 NoClassDefFoundError 问题或检测 jar 包是否被重复加载

    具体使用方法在 2.6 及 3.5 两节的案例中有介绍。

    3.5 综合案例二

    使用工具项:class loader(重复类检测)、inspector、正则检索。

    异常现象 :运行时报 NoClassDefFoundError,在 classpath 中有两个不同版本的同名类。

    分析过程

    1. 进入 MAT 已加载的重复类检测功能,方式如下图。
      在这里插入图片描述
    2. 可以看到所有重复的类,以及相关的类加载器,如下图。
      在这里插入图片描述
      3.根据类名,在框中输入类名可以过滤无效信息。
      4.选中目标类,通过Inspector视图,可以看到被加载的类具体是在哪个jar包里。(本例中重复的类是被 URLClassloader 加载的,右键点击 “_context” 属性,最后点击 “Go Into”,在弹出的窗口中的属性 “_war” 值是被加载类的具体包位置)
      在这里插入图片描述
      在这里插入图片描述

    4. 对象状态详解及实战

    4.1 inspector

    功能:MAT 通过 inspector 面板展现对象的详情信息,如静态属性值及实例属性值、内存地址、类继承关系、package、class loader、GC Roots 等详情数据。
    使用场景

    • 当内存使用量与业务逻辑有较强关联的场景,通过 inspector 可以通过查看对象具体属性值。比如:社交场景中某个用户对象的好友列表异常,其 List 长度达到几亿,通过 inspector 面板获取到异常用户 ID,进而从业务视角继续排查属于哪个用户,本例可能有系统账号,与所有用户是好友。
    • 集合等类型的使用会较多,如查看 ArrayList 的 size 属性也就了解其大小。

    举例:下图中左边的 Inspector 窗口展现了地址 0x125754cf8 的 ArrayList 实例详情,包括 modCount 等并不会在 outgoing references 展现的基本属性
    在这里插入图片描述

    4.2 集合状态

    功能:帮助更直观的了解系统的内存使用情况,查找浪费的内存空间。

    使用入口:MAT 主页 → Java Collections → 填充率/Hash冲突等功能。
    在这里插入图片描述
    使用场景

    • 通过对 ArrayList 或数组等集合类对象按填充率聚类,定位稀疏或空集合类对象造成的内存浪费。
    • 通过 HashMap 冲突率判定 hash 策略是否合理。
      具体使用方法在 4.3 节案例详细介绍。

    4.3 综合案例三

    使用工具项:Dominator tree、Histogram、集合 ratio。
    异常现象 :程序 OOM,且 Dominator tree 无大对象,通过 Histogram 了解到多个 ArrayList 占据大量内存,期望通过减少 ArrayList 优化程序。
    程序代码

    package com.q.mat;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ListRatioDemo {
    
        public static void main(String[] args) {
            for(int i=0;i<10000;i++){
                Thread thread = new Thread(new Runnable() {
                    public void run() {
                        HolderContainer holderContainer1 = new HolderContainer();
                        try {
                            Thread.sleep(1000 * 1000 * 60);
                        } catch (Exception e) {
                            System.exit(1);
                        }
                    }
                });
                thread.setName("inner-thread-" + i);
                thread.start();
            }
    
        }
    }
    
    class HolderContainer {
        ListHolder listHolder1 = new ListHolder().init();
        ListHolder listHolder2 = new ListHolder().init();
    }
    
    class ListHolder {
        static final int LIST_SIZE = 100 * 1000;
        List<String> list1 = new ArrayList(LIST_SIZE); // 5%填充
        List<String> list2 = new ArrayList(LIST_SIZE); // 5%填充
        List<String> list3 = new ArrayList(LIST_SIZE); // 15%填充
        List<String> list4 = new ArrayList(LIST_SIZE); // 30%填充
    
        public ListHolder init() {
            for (int i = 0; i < LIST_SIZE; i++) {
                if (i < 0.05 * LIST_SIZE) {
                    list1.add("" + i);
                    list2.add("" + i);
                }
                if (i < 0.15 * LIST_SIZE) {
                    list3.add("" + i);
                }
                if (i < 0.3 * LIST_SIZE) {
                    list4.add("" + i);
                }
            }
            return this;
        }
    }
    

    分析过程

    1. 使用 Dominator tree 查看并无高占比起点
      在这里插入图片描述
    2. 使用 Histogram 定位到 ListHolder 及 ArrayList 占比过高,经过业务分析很多 List 填充率很低浪费内存
      在这里插入图片描述
    3. 查看 ArrayList 的填充率,MAT 首页 → Java Collections → Collection Fill Ratio。
      在这里插入图片描述
    4. 查看类型填写 java.util.ArrayList
      在这里插入图片描述
    5. 从结果可以看出绝大部分 ArrayList 初始申请长度过大
      在这里插入图片描述

    5. 按条件检索详解及实战

    5.1 OQL

    功能:提供一种类似于SQL的对象(类)级别统一结构化查询语言,根据条件对堆中对象进行筛选。

    语法

    SELECT * FROM [ INSTANCEOF ] <class_name> [ WHERE <filter-expression> ]
    
    • Select 子句可以使用“*”,查看结果对象的引用实例(相当于 outgoing references);可以指定具体的内容,如 Select OBJECTS v.elementData from xx 是返回的结果是完整的对象,而不是简单的对象描述信息);可以使用 Distinct 关键词去重。
    • From 指定查询范围,一般指定类名、正则表达式、对象地址。
    • Where 用来指定筛选条件。
    • 全部语法详见:OQL 语法
    • 未支持的核心功能:group by value,如果有需求可以先导出结果到 csv 中,再使用 awk 等脚本工具分析即可。
    • 例子:查找 size=0 且未使用过的 ArrayList:select * from java.util.ArrayList where size=0 and modCount=0。

    使用场景

    • 一般比较复杂的问题会使用 OQL,而且这类问题往往与业务逻辑有较大关系。比如大量的小对象整体占用内存高,但预期小对象应该不会过多(比如达到百万个),一个一个看又不现实,可以采用 OQL 查询导出数据排查。
    • 例子:微服务的分布式链路追踪系统,采集各服务所有接口名,共计200个服务却采集到了200万个接口名(一个服务不会有1万个接口),这时直接在 List 中一个个查看很难定位,可以直接用 OQL 导出,定位哪个服务接口名收集异常(如把 URL 中 ID 也统计到接口中了)

    5.2 检索及筛选

    功能:本文第二章内存分布,第三章对象间依赖的众多功能,均支持按字符串检索、按正则检索等操作。

    使用场景:在使用 Histogram、Thread overview 等功能时,可以进一步添加字符串匹配、正则匹配条件过滤缩小排查范围。

    5.3 按地址寻址

    功能:根据对象的虚拟内存十六进制地址查找对象。

    使用场景:仅知道地址并希望快速查看对象做后续分析时使用,其余可以直接使用 outgoing reference 了解对象信息。

    5.4 综合案例四

    使用工具项:OQL、Histogram、incoming references
    异常现象及目的 :程序占用内存高,存在默认初始化较长的 ArrayList,需分析 ArrayList 被使用的占比,通过数据支撑是否采用懒加载模式,并分析具体哪块代码创建了空 ArrayList。

    程序代码

    public class EmptyListDemo {
        public static void main(String[] args) {
            EmptyValueContainerList emptyValueContainerList = new EmptyValueContainerList();
            FilledValueContainerList filledValueContainerList = new FilledValueContainerList();
            System.out.println("start sleep...");
            try {
                Thread.sleep(50 * 1000 * 1000);
            } catch (Exception e) {
                System.exit(1);
            }
        }
    }
    
    class EmptyValueContainer {
        List<Integer> value1 = new ArrayList(10);
        List<Integer> value2 = new ArrayList(10);
        List<Integer> value3 = new ArrayList(10);
    }
    
    class EmptyValueContainerList {
        List<EmptyValueContainer> list = new ArrayList(500 * 1000);
    
        public EmptyValueContainerList() {
            for (int i = 0; i < 500 * 1000; i++) {
                list.add(new EmptyValueContainer());
            }
        }
    }
    
    class FilledValueContainer {
        List<Integer> value1 = new ArrayList(10);
        List<Integer> value2 = new ArrayList(10);
        List<Integer> value3 = new ArrayList(10);
    
        public FilledValueContainer init() {
            value1.addAll(Arrays.asList(1, 3, 5, 7, 9));
            value2.addAll(Arrays.asList(2, 4, 6, 8, 10));
            value1.addAll(Arrays.asList(1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
            return this;
        }
    }
    
    class FilledValueContainerList {
        List<FilledValueContainer> list = new ArrayList(500);
    
        public FilledValueContainerList() {
            for (int i = 0; i < 500; i++) {
                list.add(new FilledValueContainer().init());
            }
        }
    }
    
    

    分析过程

    1. 内存中有50万个 capacity = 10 的空 ArrayList 实例。我们分析下这些对象的占用内存总大小及对象创建位置,以便分析延迟初始化(即直到使用这些对象的时候才将之实例化,否则一直为null)是否有必要。

    2. 使用 OQL 查询出初始化后未被使用的 ArrayList(size=0 且 modCount=0),语句如下图。可以看出公有 150 万个空 ArrayList,这些对象属于浪费内存。我们接下来计算下总计占用多少内存,并根据结果看是否需要优化。
      在这里插入图片描述

    3. 计算 150万 ArrayList占内存总量,直接点击右上方带黄色箭头的 Histogram 图标,这个图标是在选定的结果再用直方图展示,总计支配了120M 左右内存(所以这里点击结果,不包含 modCount 或 size 大于0的 ArrayList 对象)。这类在选定结果继续分析很多功能都支持,如正则检索、Histogram、Dominator tree等等。
      在这里插入图片描述

    4. 查看下空 ArrayList 的具体来源,可用 incoming references,下图中显示了清晰的对象创建路径
      在这里插入图片描述
      总结展望
      至此本文讲解了 MAT 各项工具的功能、使用方法、适用场景,也穿插了4个实战案例,熟练掌握对分析 JVM 内存问题大有裨益,尤其是各种功能的组合使用。在下一篇《JVM 内存分析工具 MAT 的深度讲解与实践——高阶篇》会总结 JVM 堆内存分析的系统性方法,并在更复杂的案例中实践。

    参考内容
    Q的博客

    展开全文
  • 工具MAT(MemoryAnalyzerTools)win32位工具,用来做内存分析,供JAVA或android开发者使用,解压即用相当方便,喜欢的小伙伴可以试试!
  • MemoryAnalyzer-1.3.1.20140107-win32.win32.x86_64.zip
  • MAT内存分析工具,支持版本windows64位。 最近项目遇到oom问题,上传一下查询oom的心酸路程的工具
  • 内存分析工具MAT分析内存溢出问题

    千次阅读 2019-07-30 17:22:32
    MAT下载安装: 1.在eclipse中安装插件 ...MAT分析的是hprof文件,hprof文件记录了JVM内存溢出时的堆信息,通过分析该文件我们可以分析溢出原因。 JVM参数配置: -Xms10M -Xmx10M -XX:+HeapDumpOnOutOfMemoryEr...

    MAT下载安装:

    1.在eclipse中安装插件  2.下载独立MAT:下载地址:http://www.eclipse.org/mat/downloads.php

    MAT分析的是hprof文件,hprof文件记录了JVM内存溢出时的堆信息,通过分析该文件我们可以分析溢出原因。

     JVM参数配置:

    -Xms10M -Xmx10M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\gc.hprof

           通过-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\gc.hprof 参数告诉JVM在内存溢出是记录堆信息,以及相应的hprof文件的存放位置。

          -Xms10M -Xmx10M配置10M的目的是为了内存溢出测试。

    测试代码:

    public class GcTest {
        private static final int _1MB= 1024 * 1024;  //约1m
    
        public static void main(String[] args) {
            //总共约8m多,堆大小设置不超过8388608B即8.388608m就会内存溢出,但是需要整数,小于8M就会重现这个错误
            byte[] a1, a2, a3, a4;
            a1 = new byte[2 * _1MB];
            a2 = new byte[2 * _1MB];
            a3 = new byte[2 * _1MB];
            a4 = new byte[2 * _1MB];
        }
    }

    执行出错,内存溢出。相应的hprof文件保存在相应路径下。

    通过MAT打开gc.hprof文件。

    选择File-》Open heap dump,选择gc.hprof文件

    在Leak Suspects中,我们可以看到(a) Problem Suspect 1,这就是我们要关注的内存溢出问题。它占用了6M内存。

    查看details可以看到支配树上的累积对象

     累计数根据类归类。

     

    线程堆栈信息。

    从以上结果中可以看到有3个大byte数组占用了很大的堆内存空间。

    点击视图模式查看:

     可以看到地址为0xffc394c0的线程占用了92.29%的对空间。

    展开同样可以看到3个byte数组 。

    通过以上数据进而分析内存溢出的原因,这也是解决性能问题的一种思路。

    展开全文
  • MAT(Memory Analyzer Tool)工具是eclipse的一个插件(MAT也可以单独使用),使用起来非常方便,尤其是在分析内存的dump文件时,可以非常直观的看到各个对象在堆空间中所占用的内存大小、类实例数量、对象引用关系、...
  • 内存分析工具MAT的使用 一MAT插件安装 MAT(Memory Analyzer Tool) 是基于heap dumps来进行分析的它的分析速度比jhat快分析结果是图形界面显示比java内置jhat的可读性更高,通过Eclipse市场安装 方法/步骤1 打开...
  • MAT是Memory Analyzer tool的缩写,是一种快速,功能丰富的Java堆分析工具,能帮助你查找内存泄漏和减少内存消耗。很多情况下,我们需要处理测试提供的hprof文件,分析内存相关问题,那么MAT也绝对是不二之选。 ...
  • 内存分析工具MAT的使用

    千次阅读 2016-09-23 13:09:15
    原文链接:http://www.jianshu.com/p/d8e247b1e7b2MAT简介MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。...
  • 1.1、在Eclipse上安装MAT插件,步骤如下: 点击Help,Install New Soft,就出现了以下Install界面:然后我们点击ADD,在弹出的框中填上Mat插件的地址:http://download.eclipse.org/mat/1.6/update-site/,确定后, ...
  • 1. 前言 生产环境中,尤其是吃大内存的JVM,一旦出现内存泄露等问题是非常容易引发OutofMemory的,如果没有一个好的工具提供给开发人员定位问题和分析问题,那么这将会是一场噩梦。目前JDK其实自带有一些内存泄露...
  • mat 内存分析工具 mat 内存分析工具
  • 常见内存分析工具对比 下图中 Y 表示支持,N 表示不支持,时间截至发稿前。 产品功能 MAT JProfiler Visual VM jhat jmap hprof 对象关联分析、深浅堆、GC ROOT、内存泄漏检测、线程分析、...
  • 内存分析工具 MAT 的使用

    万次阅读 多人点赞 2014-02-19 09:50:21
    内存泄漏的排查方法 Dalvik Debug Monitor Server (DDMS) 是 ADT 插件的一部分,其中有两项功能可用于内存检查 : · heap 查看堆的分配情况 · allocation tracker 跟踪内存分配情况 DDMS 这两项功能有助于...
  • MAT内存分析工具

    2018-11-14 12:02:27
    性能分析工具之-- Memory Analyzer tool(MAT) 绿色版免安装解压即可用
  • 使用 Memory Analyzer主要分析的是内存的使用情况,它能够打开的是.hprof格式的文件。为了得到该文件,我们先写好如下简单代码: package memoryManage; import java.util.*; /* * 根据书本2.4.1章节的代码书写 * ...
  • Mac os 下打开java内存分析工具 mat

    千次阅读 2018-10-15 13:25:25
    下载MAT后, 解压得到mat.app, 但是直接点击打开出错, 显示错误信息在文件 /Users/along/.eclipse/762171948_macosx_cocoa_x86_64/configuration/1539580415773.log中. 1. 打开错误信息 cat /Users/along/.eclipse/...
  • mat 内存分析工具 mat 内存分析工具 mat 内存分析工具 mat 内存分析工具
  • 简单回顾下 Java 的内存回收机制,内存空间中垃圾回收的工作由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活...
  • 在这个系列的前四篇文章中,我分别介绍了DVM、ART、内存泄漏和内存检测工具的相关知识点,这一篇我们通过一个小例子,来学习如何使用内存分析工具MAT
  • https://www.jianshu.com/p/c6e2abb9f657
  • MAT内存分析工具,如果用Android Studio进行开发则需要单独下载它

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,088
精华内容 7,235
关键字:

内存分析工具mat