Heim  >  Artikel  >  Datenbank  >  探究内存泄露—Part2—分析问题

探究内存泄露—Part2—分析问题

PHP中文网
PHP中文网Original
2017-04-01 14:44:561024Durchsuche

本文由ImportNew-黄索远翻译自captaindebug ImportNew注:如果你也对Java技术翻译分享感兴趣,欢迎加入我们的Java开发小组。参与方式请查看小组简介。 如果你看过这篇博客的第一部分,就会知道在展示的内存泄露示例代码使用生产者-消费者模型创建了一个模拟

  本文由 ImportNew - 黄索远 翻译自 captaindebug

ImportNew注:如果你也对Java技术翻译分享感兴趣,欢迎加入我们的 Java开发 小组。参与方式请查看小组简介。

如果你看过这篇博客的第一部分,就会知道在展示的内存泄露示例代码使用生产者-消费者模型创建了一个模拟股票交易的应用,所有的交易命令都被存入一个虚拟的数据库中。示例代码故意留下了一个缺陷(OrderRecord线程处理一条命令后sleep一段时间),使得OrderRecord线程消费命令的速度跟不上OrderFeed线程生产命令的速度。这就意味着存储命令的队列会变得越来越长,直到最后内存溢出程序崩溃。问题是,如果只看我的代码,确实能够很轻松得看出哪里出了差错;但是如果出问题的代码你从未看过并且代码又长又复杂,加之没有监控线程来帮助你观察队列大小或者其他内部信息,这时该怎么办呢?

下面向大家介绍分析程序内存泄露问题的三个步骤:

  1. 提取发生内存泄露的服务器的转储文件。

  2. 用这个转储文件生成报告。

  3. 分析生成的报告。

有几个工具能帮你生成堆转储文件,分别是:

  • jconsole

  • Jvisualvm

  • Eclipse Memory Analyser Tool(MAT)

用jconsole提取堆转储文件

将jconsole关联你的应用:单击MBeans选项卡打开com.sun.management包,点击HotSpotDiagnostic,点击Operations选择dumpHeap。这时你将会看到dumpHeap操作:它接受两个参数p0和p1。在p0的编辑框内输入一个堆转储的文件名,然后按下DumpHeap命令。

1386.png

用jvisualvm提取堆转储文件

连接示例代码,右键点击你的应用,在左侧的“application”窗格中选择“Heap Dump”。

注意:如果你在发生内存泄露的服务器上有一个远程连接,那么jvisualvm将会把转出文件保存在远程机器(假设这是一台unix机器)上的/tmp目录下。你不得不将这个文件通过FTP传送到你的机器上,然后再进行研究。

1387.png

用MAT来提取堆转储文件

jconsole和jvisualvm本身就是JDK的一部分,而MAT或者称作“内存分析工具”,是一个基于eclipse的工具。你可以从eclipse.org下载。

最新版本的MAT需要你在电脑上安装JDk1.6。如果你用的是Java1.7版本也不用担心,因为它会自动为你安装1.6版本,并且不会和安装好了的1.7版本产生冲突。

1388.png

使用MAT的时候,只需要点击“Aquire Heap Dump”,然后遵循指示就可以了。

1389.png

远程连接

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

何时提取堆转存文件

这需要耗费一点心力和运气。如果太早提取了堆转储文件,那么你将不能发现问题。因为它们被合法,非泄露类的实例屏蔽了。不过也不能等待太久,因为提取堆转储文件需要占用内存,进行提取操作的时候可能会导致你的应用崩溃。

1390.png

最好的办法是将jconsole连接到你的应用程序并监控堆的占用情况,知道它看起来像在崩溃的边缘。这样很容易就能监控到,因为没有发生内存泄露时,三个堆部分指标都是绿色的。

1391.png

分析转储文件

现在轮到MAT发挥作用了,因为它本身就是被设计用来分析堆转储文件的。要打开和分析一个堆转储文件,选择File选项下的Heap Dump选项。选择了你要打开的文件后,你将会看到如下三个选项:

1392.png

选择Leak Suspect Report选项。在MAT翻腾几秒后,会生成这样的一个页面:

1393.png

如饼状图显示:在示例中,疑似有一处发生了内存泄露。也许你会想,这样的做法只有在代码受到控制的情况下才可取。毕竟这只是个例子,这又能说明什么呢?好吧,我承认在这个例子里,所有的问题都是可见的;线程a占用了98.7MB内存,其他线程用了1.5MB。在实际情况中,你得到的图表是这样的。

下一步要做的就是挖得更深一点……

1394.png

如上图所示,报告的下一部分告诉我们,有一个LinkedBlockQueue占用了98.46%的内存。想要进一步的探究,点击Details>>。

1395.png

可以看到,问题确实是出在我们的orderQueue上。这个队列里存储了所有生成的虚拟命令,并且可以被我们上篇博文里提到的三个线程OrderFeed、OrderRecord、OrderMonitor访问。

那么一切都清楚了,MAT告诉我们:示例代码中有一个LinkedBlockQueue,这个队列用尽了所有的内存,从而导致了严重的问题。不过我们不知道这个问题为什么会产生,也不能指望MAT告诉我们。这个问题,如阿加莎·克里斯蒂笔下的赫尔克里·波洛所说,得用“泽灰色小细胞”解决……

 以上就是探究内存泄露—Part2—分析问题的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:mySql存储过程的结构Nächster Artikel:mysql limit