作者 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. Android 使用剪贴板传递简单数据及复杂数据的方法

    传递数据的场景在于不同页面之间跳转,需要携带数据:简单数据值指的是String, int等数据, 复杂数据指的是类 1.   使用剪贴板传递简单数据方法: 第一个页面里面放数据操作如下: Clipbo ...

  2. 菜鸟之路——Linux基础::计算机网络基础,Linux常用系统命令,Linux用户与组权限

    最近又重新安排了一下我的计划.准备跟着老男孩的教程继续学习,感觉这一套教程讲的很全面,很详细.比我上一套机器学习好的多了. 他的第一阶段是Python基础,第二阶段是高等数学基础,主要将机器学习和深度 ...

  3. Android之Bitmap 高效加载

    一张图片(BitMap)占用的内存=图片长度*图片宽度*单位像素占用的字节数 图片格式(Bitmap.Config) 一张100*100的图片占用内存的大小 ALPHA_8 图片长度*图片宽度 100 ...

  4. PAT1022

    输入两个非负10进制整数A和B(<=230-1),输出A+B的D (1 < D <= 10)进制数. 输入格式: 输入在一行中依次给出3个整数A.B和D. 输出格式: 输出A+B的D ...

  5. Git详解之二 Git基础 转

    http://www.open-open.com/lib/view/open1328069733264.html Git 基础 读完本章你就能上手使用 Git 了.本章将介绍几个最基本的,也是最常用的 ...

  6. 使用SS5搭建linux下的sock5代理服务器

    http://sourceforge.net/projects/ss5/下载最新源码 apt-get install libpam0g-dev apt-get install libldap2-dev ...

  7. CF 964C Alternating Sum

    给定两正整数 $a, b$ .给定序列 $s_0, s_1, \dots, s_n,s_i$ 等于 $1$ 或 $-1$,并且已知 $s$ 是周期为 $k$ 的序列并且 $k\mid (n+1)$,输 ...

  8. web标准,可用性和可访问性

    web标准,简单的说,是指html,css,JavaScript三者的分离. 网页由三部分组成:结构,表现和行为.对应的标准分为三方面: 1.结构化标准语言XHTML和XML2.表现标准语言主要包括c ...

  9. BZOJ3612 [Heoi2014]平衡 整数划分

    [Heoi2014]平衡 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 348  Solved: 273[Submit][Status][Discus ...

  10. pat 甲级 Public Bike Management

    Public Bike Management (30) 题目描述 There is a public bike service in Hangzhou City which provides grea ...