作者 Rave_Tian
2016.02.01 17:56* 字数 2988 阅读 520评论 0喜欢 0

分析和理解应用的内存使用情况是开发过程中一项不小的挑战。一个微小的逻辑错误可能会导致监听器没法被释放回收,最终导致可怕的内存溢出问题。甚至有时你已经释放了所有空对象,但是你的应用却多消耗了十倍甚至百倍的内存导致效率很低。

幸运的是,Eclipse Memory Analyzer(MAT)能给我提供应用的内存使用情况的详细信息帮助我们进行内存分析。这款工具不仅能有效的追踪内存泄漏,还能周期性的审查系统的状态。在本课程我将列出10条小技巧帮助你更高效的使用MAT。如果你是一名Java开发者,Eclipse Memory Analyzer Tool是你调试工具箱里必不可少的。

[ 你还在寻找更多工具吗? 查看Eclipse Tools页面. | 使用Yoxos.Create a free profile now让你更方便的管理你的Eclipse workspace. ]

可以使用Install New Software对话框或者通过EclipseMarketPlace来安装MAT。你也可以安装使用Yoxos将其囊括到你自己的Eclipse中。

在本例中,我们使用一个非常简单的方案,通过分配100,000监听器,并将它们存储到4个列表中。在未将列表清空回收的情况下让应用休眠。

1.获取内存快照(Heap Dump)


你可以通过下面的几种方式使用MAT:

1.配置一款应用,当其发生内存溢出错误的时候将其内存镜像导出,

2.将MAT连接到一个已存在的Java进程,或者

3.手动获取heap dump并加载到MAT中。

无论哪种情况,你都需要记住这只是内存在某一时间节点的快照。MAT不能告诉你为什么一个对象会被创建,也不能显示那些已经被回收掉的对象。但是,如果你使用MAT结合其他的调试工具和调试技术,通常会非常快的解决内存泄漏。

你可以通过添加下面的vm argument,配置你的应用当其抛出OutOfMemory错误的时候导出heap dump:

-XX:+HeapDumpOnOutOfMemoryError

另外,你也可以使用jstack从正在运行的Java进程中获取Heap dump.

jmap -dump:file=heap.bin

最后,你还可以使用MAT的Acquire Heap Dump动作选中你本地机器上已经存在的Java进程。

当你第一次加载Heap dump的时候,MAT需要花几分钟时间来给Heap dump编辑索引。其结果会保留所以后续的再次加载会很快。

2.理解Histogram


当你第一次获取heap dump的时候,MAT会给你展示应用的内存使用情况的overview。

中间的饼状图给你展示的是retained size最大的对象。也就是说,如果我们能释放一个特殊的java.lang.Thread对象,就能保留11.2Mb的内存,超过你当前应用使用内存的90%。有趣的是,java.lang.Thread并不像是问题的症结所在。为了更好的理解到系统当前存在的对象,我们可以使用Histogram。

Histogram可以展示某个特定类的对象个数和每个对象使用的内存。当然char[],String和Object[]都不太会导致内存问题。为了更好的组织这个视图,你可以通过classloader或者package来分组。这会让你更好的专注在你自己的对象上。

Histogram 也能使用正则表达式来过滤。例如,我们可以只展示那些匹配com.example.mat.*的类。

通过这个视图我们可以看见在系统中存在100,000个Listener的对象我们也可以看见每一个对象正在占用的内存数量。这里有两个数值,Shallow HeapRetained Heap。Shallow heap是一个对象消费的内存数量每个对象的引用需要32(或者64 bits,基于你的CPU架构)。基本数据类型例如整形和长整形需要4或者8 bytes以及其他的。其实更有用的参数是Retained Heap.

3.理解Retained Heap


Retained Heap显示的是那些当垃圾回收时候会清理的所有对象的Shallow
Heap的总和。举例说明,如果一个ArrayList包含100,000成员项,每个成员需要16
bytes,当移除这个ArrayList的时候会释放16x100,000+X(bytes),X是ArrayList的shallow
size。(注:这是假设这些对象只被这个ArrayList引用,没有其他地方引用)。

Retained heapRetained set(保留集)里面所有对象大小的求和计算结果。Retained set of X指的是这样的对象集合: X 对象被 GC 回收后,所有能被回收的对象集合。

Retained heap有两种不同的计算方式, 使用quick approximation或者precise retained size.

通过计算Retained Heap我们可以看见com.example.mat.Controller持有了大部分的内存,尽管他自身只占用了24 bytes。所以通过找到方法释放Controller,我们就能毫无疑问的控制好内存问题。

4. Dominator Tree(支配树)


查看Dominator tree是理解Retained heap的关键。Dominator
tree是由你系统中的复杂的Object graph(对象引用图)生成的树状图。Dominator
tree可以让你分别出最大内存图表。如果所有指向对象Y的路径都经过对象X,则认为对象X支配对象Y。通过查看本例的Dominator
tree,我们开始明白到底是哪些内存块发生了泄露。

通过查看dominator tree,我们可以轻易的了解到并不是java.lang.Thread导致的问题,反而是ControllerAllocator持有内存。Controller保留了全部100,000个Listeners对象。我们可以通过释放这些对象,或释放他们所包含的lists来改善内存情况。下面列出几条dominator tree的属性:

● 对象X的子树中的所有对象(本例中的com.example.mat.Controller)被称作对象A的Retained set(保留集)。

● 如果对象X是对象Y的直接支配者(Controller就是Allocator的直接支配者),那么X的直接支配者(本例中的java.lang.Thread)也只配Y对象。

● 支配树中节点的父子关系跟对象引用图中的不直接对应。

通过Histogram你也可以选择某个类,然后找到所有支配该类的实例的对象。

5. 探索Paths to the GC Roots


 
 

有时候有一些你确信已经处理了的大的对象集合。通过查找支配者可能会有用,但是通常我们希望能得到这个对象节点到GC根节点的路径。例如,如果我现在释放了Controller对象,会理所当然的以为已经解决内存问题,不幸的是这并没有用。如果现在选中一个Listener的对象,然后查看他到GC根节点的路径。我们可以看见Controller类(注:是类,而不是对象)引用到了一个Listener队列。这是因为这些队列当中有一个被声明成静态队列。

你也可以查看到这个对象所有被引用到的地方和这个对象持有的引用。当你想要在对象引用图中查看某个特定对象的所有引用关系的时候,这是非常有用的。

6. Inspector


Inspector展示的是当前选中类或对象的详细信息。在本例中我们可以看见选中的ArrayList包含100,000元素和一个指向地址为0x7f354ea68的对象数组的引用。

Inspector和Snapshot linked会给你提供一些选中项的重要统计数据。

7. Common Memory Anti-Patterns


MAT使用反模式提供了公用存储器的详细报告。.能用其来搞明白哪里的发生了内存泄漏,或通过它找到一些简单的清理手段来优化性能。

Heap Dump Overview展示了Heap Dump的详细信息和一些常用工具的链接(比如Histogram)。信息主要有系统中正在运行的线程、对象的总数、堆的大小等。

Leak Suspects报告显示了MAT发现的可能导致内存泄漏的地方,和用于分析这些发现的工具和图表的链接。

另一个使用到反模式的情况是,当系统有大量的集合,但是每个集合只有少量元素的时候。例如,如果每一个监听器都对应一组通知者(需要某些事件来触发的列表项),但是这些通知者只是偶尔触发,我们就应该制止这种浪费内存的行为。Java Collections工具可以帮你处理这类问题。

通过Collection -> Fill Ratio Report我们可以看见100,000个队列是空的。如果我们能够用一种便捷的方式来分配这些内存(当我们需要的时候),我们可以节约大概8Mb内存。

我们也可以通过分析集合来查看array fill ratioscollection size statisticsmap collision ratios

8. Java工具


MAT量身定制了许多内置的工具用来生成Java运行环境细节的相关报表。For example, thereport will show details about all the treads in the system.例如,Threads and Stack可以展示系统中所有线程的细节。你可以看见每个栈中当前存在的本地变量

你可以通过特定的模板来检索所有匹配的字符串:

甚至可以检索那些包含了浪费内存的字符数组的字符串(这种情况经常是因为反复是用substring方法导致的)。

9. Object Query Language


综合以上所说,Eclipse Memory
Analyzer提供了很多用来追踪内存泄漏和内存过量使用的工具。大多数的内存问题可以通过上面的工具定位到,但是Heap
Dump包含了更多的信息。Object Query Language  (OQL)让你可以基于Heap Dump创建你自己的报表。

OQL是一种类似于SQL的语言。只需要将类当成表,对象看做行,字段看做列。例如,想要查询com.example.mat.Listener的所有对象,只需要写:

select * from com.example.mat.Listener

表的列可以通过不同的字段来设置,例如:

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

And finally, the WHERE clause can be used to specify particular
criteria, such as all the Strings in the system which are not of the
format
“message:.*”最后WHRER子句可以用来筛选特定的条件,例如可以通过下列语句找出系统中所有不匹配"message:.*"的字符串:

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

10.导出结果


MAT是一款用来导出应用内存状态相关报告的利器。Heap
Dump包含了有关你系统的非常有价值的信息。并且MAT提供了相关的工具来接入这些数据。然而,就像很多开源工具一样,如果你对于某些失误不太敏感,或者你运气不好。使用MAT可以将结果导出成包括HTML,CSV甚至纯文本格式。你可以使用电子表格程序(或者你自己的工具)来继续进行分析。

MAT是一款强大的工具,一款Java开发者应该熟知的工具。追踪内存泄漏和其他的一些内存问题对开发者来说是常见的难点,可喜的是有MAT可以迅速的帮你找到与你内存问题的源头所在。

英文原文:10 Tips for using the Eclipse Memory Analyzer « EclipseSource Blog

参考:Android 内存剖析 - 发现潜在问题 - ImportNew

(译)关于使用Eclipse Memory Analyzer的10点小技巧的更多相关文章

  1. 一次使用Eclipse Memory Analyzer分析Tomcat内存溢出

    转:http://tivan.iteye.com/blog/1487855 前言 在平时开发.测试过程中.甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严 ...

  2. 一次使用Eclipse Memory Analyzer分析Tomcat内存溢出(转)

    前言 在平时开发.测试过程中.甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严重的问题.我们需要找造成OutOfMemoryError原因.一般有两种情况 ...

  3. 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    Eclipse Memory Analyzer(MAT)是著名的跨平台集成开发环境 Eclipse Galileo 版本的 33 个组成项目中之一,它是一个功能丰富的 JAVA 堆转储文件分析工具,可 ...

  4. mat 使用 分析 oom 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    概述 对于大型 JAVA 应用程序来说,再精细的测试也难以堵住所有的漏洞,即便我们在测试阶段进行了大量卓有成效的工作,很多问题还是会在生产环境下暴露出来,并且很难在测试环境中进行重现.JVM 能够记录 ...

  5. [Android Memory] 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    转载地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html Eclipse Memory Analyzer ...

  6. [转]一次使用Eclipse Memory Analyzer分析Tomcat内存溢出

    一次使用Eclipse Memory Analyzer分析Tomcat内存溢出 前言 在平时开发.测试过程中.甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序 ...

  7. 使用Eclipse Memory Analyzer Tool(MAT)分析故障

    Eclipse Memory Analyzer Tool(MAT)是一个强大的基于Eclipse的内存分析工具,可以帮助我们找到内存泄露,减少内存消耗. 工作中经常会遇到一些内存溢出.内存泄露等问题, ...

  8. MyEclipse安装Eclipse Memory Analyzer插件,并进行错误文件分析流程

    在看深入JVM虚拟机一书(p50,2.4 实战OutOfMemoryError),有一个Java堆溢出的例子,使用到了Eclipse Memory Analyzer插件,由于自己现在使用的是MyEcl ...

  9. 使用Eclipse Memory Analyzer Tool(MAT)分析线上故障(一) - 视图&功能篇

    Eclipse Memory Analyzer Tool(MAT)相关文章目录: 使用Eclipse Memory Analyzer Tool(MAT)分析线上故障(一) - 视图&功能篇 使 ...

随机推荐

  1. Bat windows 批处理 常用命令

    设置全屏: To make all bat files fullscreen: reg add HKCU\Console\ /v Fullscreen /t REG_DWORD /d /f To ma ...

  2. Linux下c++使用pthread库

    pthread 库是纯c库,没有类指针的概念,当想phread_create中传递类成员函数时,就会报错,这里针对这种情况,对线程创建做了必要封装,较为简单,继承类,实现run接口,然后使用start ...

  3. (转载)CentOS 6.5使用aliyun镜像来源

    (原地址:http://www.linuxidc.com/Linux/2014-09/106675.htm) 当我们把CentOS 6.5安装好以后,可以使用这个脚本来使用国内的阿里云镜像源 #!/b ...

  4. android AsyncTask使用限制

    由于AsyncTask内部是使用线程池(ThreadPoolExecutor)来管理要处理的任务的,所以AsyncTask的弊端就非常明确了:要extcute的任务数量超过线程池最大容量时,必然会报错 ...

  5. python基础-集合小结

    Python-基础-集合小结 集合 简介 声明 常用操作 成员关系 新增删除 集合间操作 其他 补充 集合 简介 python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和 ...

  6. POJ 3249:Test for Job(拓扑排序+DP)

    题意就是给一个有向无环图,每个点都有一个权值,求从入度为0的点到出度为0点路径上经过点(包括起点终点)的权值和的最大值. 分析: 注意3点 1.本题有多组数据 2.可能有点的权值是负数,也就是结果可能 ...

  7. MFC 禁用输入法

    #include <Imm.h> HIMC m_hImc; // 全局或者成员变量 // Function for Disabling IME void CMyDialog::Disabl ...

  8. Flask request获取参数问题

    https://www.jianshu.com/p/ecd97b1c21c1 https://blog.csdn.net/lovebyz/article/details/52244330 https: ...

  9. hdu 3535 背包综合题

    /* 有n组背包,每组都有限制 0.至少选一项 1.最多选一项 2.任意选 */ #include <iostream> #include <cstdio> #include ...

  10. C 语言 和 python 调用 .so 文件

    什么是静态库和动态库, 看一篇博客 http://www.cnblogs.com/skynet/p/3372855.html 现在,我们首先生成.so文件 首先, 我们写一个a.c文件 1 2 3 4 ...