1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Eclipse Memory Analyzer分析内存使用总结

Eclipse Memory Analyzer分析内存使用总结

时间:2021-04-04 19:58:26

相关推荐

Eclipse Memory Analyzer分析内存使用总结

前言

内存泄露和内存溢出的区别:内存泄露从老年代的增长情况看是缓慢上升的, 最终达到老年代上限才会导致溢出,有些内存泄露可能需要很长的时间发生, 所以说内存泄露更隐蔽, 不像内存溢出那样容易暴露(内存溢出直接抛出OOM), 而且内存长时间得不到释放会导致服务性能越来越差、gc时间变长、响应变慢:

1. 安装

在Eclipse help -> Eclipse Marketplace下搜索Memory:

按照操作流程安装完成,重启Eclipse.

2.获取Heapdump 文件

方法1

**/jdk/1.7.0_95l64/bin/jmap -dump:format=b,file=heapdump_name.hprof <pid>

方法2.

如果你的是spring boot项目且暴露了actuator里面的heapdump的api. 直接用下面的命令。

*/actuator/heapdump

可以每隔一段时间获取一个heapdump文件

3.Histogram查询

利用Elipse 里Memory Analysis view打开你想分析的heapdump文件

打开Histogram

它按类名将所有的实例对象列出来,可以点击表头进行排序,在表的第一行可以输入正则表达式来匹配结果:

4. 使用 Compare Basket 功能分析

利用Elipse 里Memory Analysis view依次打开多个heapdump文件

1.菜单栏 window → compare basket ,打开比较窗口(如果最下面一栏已经有compare basket则这步不需要),如下图:

2. 依次打开3个dump的dashboard面板, 在下方的 Actions一栏点击"histogram"或"dominator tree"生成对应的直方图或支配树列表,如下图:

直方图或支配树都可以列出堆中存活的所有对象,但二者的维度不同, 直方图按照类型统计, 支配树是以对象维度统计。

如果你对项目代码比较熟悉, 通过直方图定位内存泄露会更快,因为它是按照类型全部平铺开的,如果这个项目不是你负责的, 建议使用支配树的方式, 因为支配树包含了对象之间的引用关系(支配树视图可以展开查看内部引用层级)

3. 我们以支配树做比对, 在最下面一栏的"Navigation History (window → navigation history)"里(直方图类似)找到在第2步打开的支配树dominator tree图标, 右键添加到compare basket, 如下图:

添加好后,打开Compare Basket面板,得到结果:

4.重复上面的2, 3步骤依次把其他的dump文件添加到"compare basket"栏, 然后点击右上角的红色感叹号, 生成比较结果,如下图:

(注意比较的dump文件的顺序,时间最早的在上面,可以通过右上角的上箭头↑和下箭头↓调整顺序)

生成的比对结果如下:

Shallow Heap一列后面的序号 #0, #1, #2 分别对应:

第一个dump文件占用的shallow size, 第二个dump文件占用的shallow size , 第三个dump文件占用的shallow size

Retained Heap #0, Retained Heap #1, Retained Heap #2 这3列分别对应:

第一个dump文件占用的retained size, 第二个dump文件占用的retained size , 第三个dump文件占用的retained size

红框圈出的是内存连续增长的对象, 可以通过右边红框的retained heap看出内存变大的趋势

绿框圈出的是没有变化的对象(至少在这3次比较中没有变化),

蓝框圈出的是内存占用下降的对象

一般我们主要关注红框标出的对象, 因为这部分发生内存泄露的嫌疑最大

这里先区分两个概念:

Shallow Size

对象自身占用的内存大小,不包括它引用的对象。

针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。

针对数组类型的对象,它的大小是数组元素对象的大小总和。

Retained Size

Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)

Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。

因为这里我们比较的是支配树, 所以按照retained heap倒序排列, 从左到右依次为: retained heap #0 → retained heap #1 → retained heap #2(以最后一个retained heap #2 倒序, 因为这个是最后一次dump的内存快照, 这样可以看出内存泄露的增长趋势)

5. 使用 Path To Gc Root 定位业务代码

还有另外一个内存泄露的嫌疑是"com.*.common.utils.ITextRendererPoolManager", 如上面比对结果的图:

单独在dominator tree支配树视图展开如图所示:

ITextRendererPoolManager内部使用了apache的一个对象缓冲池, 目的可能是为了对象复用, 继续展开,如下图:

发现是pdf的一个工具类:org.xhtmlrenderer.pdf.ITextRenderer, 这个开源的pdf工具是我们项目的邮件功能在发送附件的时候生成pdf文档时引入的一个第三方jar包,开始怀疑是否是这个开源的pdf工具导致的内存泄露, 但是不清楚这个jar包是在哪里调用的?

这里可以通过"path to gc root"查看是谁在引用他, 即我们业务代码调用的地方,如下图:

这里先说下"path to gc root"选项的含义:

with all references : 所有引用, 包括强引用, 弱引用, 软引用, 虚引用

exclude weak reference : 排除弱引用

exclude soft reference : 排除软引用

。。。。

我们知道软引用, 弱引用这些在发生full gc时可能会被回收掉(回收时机不同, 具体可自行百度), 目的是不造成内存溢出。 一般引起内存溢出的都是强引用,所以你可以选择"exclude all ptantom/weak/soft reference"只查看强引用。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。