关于使用Eclipse Memory Analyzer的10点小技巧

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

幸运的是,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

扫码关注我,一起交流学习
扫码加入QQ群共享资源
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容