学会使用eclipse Memory Analyzer --MAT

原文

mat是一个分析java内存的神器。经常用于线上出现bug后的分析,尤其oom这种错误。自己写肯定没大神牛逼,所以google了篇文章介绍给大家。

译文:
(前言省略一万字)
在这个例子中,我们使用的是一个非常简单的程序,分配100000的listener,并将它们存储在4个不同的list。应用程序然后sleep并没有清除这些list。

获取内存快照(heap dump)

以下几种方法:

  1. 配置jvm,当发生oom自动heap dump
  2. 通过mat连接到java process(这种方法基本忽略)
  3. 手动heap dump

在所有情况下,重要的是要记住,这是一个在某个时间点的内存快照。mat不能告诉你为什么一个对象被创建,也不能显示被垃圾回收的对象。然而,如果你使用mat,能够很快发现内存泄漏的原因。

配置你的应用程序当OutOfMemory错误抛出产生heap dump,添加下面的jvm参数:

-XX:+HeapDumpOnOutOfMemoryError

或者,您可以使用jstack从目前运行的java程序获得一个heap dump。
在这里插入图片描述

-XX:+HeapDumpOnOutOfMemoryError

了解直方图

mat会告诉你内存使用的大概情况

在这里插入图片描述

在中间的饼图显示了retained size的最大的对象。
这就意味着如果我们可以处理一个特定的实例java.lang.thread,我们会释放11.2mb,约占应用程序中使用此内存90%。虽然这可能看起来很有趣,java.lang.thread并不是这里的真正问题。为了更好的了解什么对象s还存在,你可以使用直方图。

在这里插入图片描述

直方图显示一个特定的类的实例的数量和每一个使用的内存。
当然 char[], String and Object[] 不可能是问题。你可以选择按找classloader 或者 package分类。更好的找到你要找的对象。
在这里插入图片描述

直方图也可以使用正则表达式过滤。例如,我们可以只显示匹配模式的类com.example.mat *。
在这里插入图片描述

现在看到,1000个listenner存在内存中。可以看到每个内存的对象的大小。有两种形式,一种是shallow heap,一种是retained heap。shallow heap是一个对象引用消耗的内存量,一个对象需要32位(或64位,这取决于架构)来作为每个引用。比如integer和long需要4或8个字节。.其实最有用的参考是retained heap。

了解retained heap

retained heap是当一个对象被回收时,他相关的所有 shallow heap的数量被释放的总和。例如,一个arraylist有100000的item,每个需要16byte,当回收该list就会释放16* 100000 + x的字节(retained heap),x就是list自己引用所占内存大小,也就是(shallow heap)

retained heap 的大小可以根据 retained set进行设置。retained heap 是对象的集合。
retained heap 可以在两种不同的方式计算,使用快速逼近或保留精度。

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

通过计算retained heap现在我们可以看到,com.example.mat.controller占据大多内存,即使只有24个字节本身。通过合适的方式释放controller,我们可以解决问题。

支配树

寻找支配树是理解retained heap的关键。支配树是复杂的对象构成的图。支配树可以让你找出最大object graph(object graph 详解
)。一个对象x称为控制对象Y,如果每个路径从根到Y都必须通过X的话。看支配树,可以找到内存的泄露点。
在这里插入图片描述

通过支配树,我们可以很容易地看到,这不是java.lang.thread的问题,而是controller和allocator所占据的内存。所有100000个listnner都被controller保留。通过删除释放这些对象,或释放它们所包含的list,我们可以改善内存情况。下面是几个支配树有用的关系:

  1. 所有对象属于子树X(比如com.example.mat.controller)那就是在x的retained set。
  2. 如果X是Y的直接支配(controller是allocator直接支配),那么X的直接统治者(在我们的例子中是java.lang.thread)还主宰着Y.
  3. 树中的父-子关系不一定对应于object graph中的关系

从直方图,你也可以选择一个特定的类,并找到所有的对这个类占据主导的对象。
在这里插入图片描述

探索到达GC根的路径

有时,你有一个大集合的对象,你确定已经处理掉了。找到支配者可能有帮助,但往往你想要准确的路径从对象到根。例如,如果我现在正确处理controller,那么肯定我的内存问题解决了,不幸的是,没解决。如果我现在选择一个listener实例,并查看路径到GC root,我可以看到,controller类(注:类,而不是一个对象)引用一个列表的listener。这是因为有一个list被声明为静态的。
在这里插入图片描述

您也可以探索一个对象的所有传入和传出的引用。这是非常有用的,如果你想看到对象的所有引用在对象图中。

The ‘Inspector’

insepector 提供当前选定的类或对象的详细信息。在这个例子中我们可以看到,当前选定的数组包含100000个元素和引用的内存位置0x7f354ea68对象数组。

在这里插入图片描述

Common Memory Anti-Patterns

mat提供了常见的内存报告通过反模式。这些可以用来获得一个内存泄漏的原因,或清理一些无用的内存占用,以帮助提高性能。

在这里插入图片描述

Heap Dump Overview显示您的heap dump的详细信息,并提供链接到常见的工具(如直方图)。信息,如运行的线程,系统中的对象的总数,堆的大小,也显示。

在这里插入图片描述

该漏洞的报告显示可能的内存泄漏,并提供链接到工具和图表来分析这些研究结果。

在这里插入图片描述

另一种常见的反模式是大量的集合的使用,每一个都有很少的entry。例如,如果我们的listener都有通知数组(需要通知某些事件的项目),但这些通知只是偶尔使用,我们会浪费很多空间。java集合工具可以帮助这些问题。

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

通过 Collection -> Fill Ratio Report 我们可以看到100,000 的list是完全空的。如果能够等到要用再创建,将会节省8mb。
也可以通过 array fill ratios, collection size statistics 和 map collision ratios. 来数组分析。

java 工具

有一些内置的工具来生成定制的java运行时的详细报告。例如,线程和堆栈的报告将显示系统中所有的thread细节。您可以看到当前在每个堆栈上活着的局部变量。

在这里插入图片描述

也可以通过Find all the Strings找到匹配的string

在这里插入图片描述

甚至在系统中找到字符串在他们的字符数组包含的浪费空间(通常是由于子串的重复使用)。
在这里插入图片描述

对象查询语言

正如我们所显示的那样,内存分析器有很多工具来帮助跟踪内存泄漏和内存过量使用。虽然大多数内存问题可能会解决使用上面所描述的技术,一个heap dump包含更多的信息。对象查询语言(OQL)允许你基于一个heap dump结果建立你自己的报告。

这是一个类似SQL的语言了。只要把类作为表,object作为行,field字段作为列。例如.展示com.example.mat.listener所有对象,你可以这样写:

select * from com.example.mat.Listener

在这里插入图片描述

列可以使用不同的字段来进行配置,如:

SELECT toString(l.message), l.message.count FROM com.example.mat.Listener l

在这里插入图片描述

最后,在其中的子句可以用来指定特定的标准,如找出系统中的所有字符串都不是这种格式的“msg:*”

SELECT toString(s), s.count FROM java.lang.String s WHERE (toString(s) NOT LIKE "message.*")

在这里插入图片描述

导出结果

内存分析器是一个伟大的工具,用于创建应用程序存储器的状态的报告。一个heap dump包含了关于系统状态的有价值的信息,并且mat提供了访问该数据所需的工具。mat可以导出结果的几种不同的格式,包括HTML,CSV或纯文本。然后,您可以使用您最喜欢的电子表格程序(或自己的工具)来继续你的分析。

在这里插入图片描述

Eclipse mat是一个功能强大的工具,一个java开发人员应该熟悉。跟踪内存泄漏和其他内存相关的问题往往是具有挑战性的,但希望mat可以帮助你快速找到问题所在。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Eclipse Memory Analyzer(简称MAT)是一款Java内存分析器,可以帮助开发人员找出Java应用程序中的内存泄漏和性能问题。以下是使用MAT的步骤: 1. 下载并安装Eclipse MAT插件:MAT是一个Eclipse插件,因此需要先安装Eclipse。然后在Eclipse中打开“Help”菜单,选择“Eclipse Marketplace”,搜索“Memory Analyzer”,安装“Memory Analyzer (MAT)”插件。 2. 导出Java堆转储文件:在Java应用程序出现内存问题时,可以使用Java虚拟机提供的命令生成Java堆转储文件(.hprof文件)。例如,可以使用以下命令生成Java堆转储文件: ``` jmap -dump:format=b,file=heapdump.hprof <pid> ``` 其中,<pid>是Java应用程序的进程ID。 3. 打开Java堆转储文件:在Eclipse中,选择“File”菜单,选择“Open Heap Dump”,并选择生成的Java堆转储文件。 4. 分析Java堆转储文件:在MAT中,可以使用各种工具和视图来分析Java堆转储文件,例如: - “Histogram”视图:显示Java堆中各个对象的数量和占用内存大小。 - “Dominator Tree”视图:显示Java堆中对象之间的继承关系,并计算每个对象及其子对象占用的内存大小。 - “Leak Suspects”视图:检测可能存在内存泄漏的对象,例如无法回收的对象或静态变量引用的对象。 MAT还提供了一些分析工具和插件,例如: - “Path to GC Roots”工具:查找对象到Java堆根之间的引用链。 - “Compare to Baseline”插件:比较两个Java堆转储文件之间的差异。 以上是使用MAT的基本步骤,使用MAT还需要一定的Java虚拟机和内存管理知识。熟练使用MAT可以帮助开发人员更好地解决Java应用程序中的内存问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值