如何找到Java内存泄漏

如何找到Java中的内存泄漏(例如,使用JHat)? 我已经尝试在JHat中加载堆转储以获得基本的外观。 但是,我不明白我应该如何能够找到根引用( ref )或任何它被称为。 基本上,我可以告诉有几百兆哈希表条目([java.util.HashMap $条目或类似的东西),但地图遍布的地方…有没有办法搜索大地图,或者找到大对象树的一般根源?

[编辑]好吧,我已经阅读了答案,但我们只是说我是一个便宜的混蛋(这意味着我更感兴趣学习如何使用JHat比支付JProfiler)。 此外,JHat始终可用,因为它是JDK的一部分。 除非JHat没有办法,否则蛮力,但我不敢相信可以这样。

此外,我不认为我将能够实际修改(添加所有地图大小的日志记录)并运行足够长的时间,以便我注意到泄漏。

我使用以下方法在Java中查找内存泄漏。 我已经使用jProfiler获得了巨大的成功,但是我相信任何具有图形功能的特殊工具(diffs更容易以图形的形式进行分析)都可以工作。

  1. 当所有的初始化完成并且应用程序处于空闲状态时,启动应用程序并等待到“稳定”状态。
  2. 运行怀疑产生内存泄漏的操作几次,以允许任何缓存,DB相关的初始化发生。
  3. 运行GC并记录内存快照。
  4. 再次运行该操作。 根据操作的复杂性和所处理数据的大小,操作可能需要运行多次或多次。
  5. 运行GC并记录内存快照。
  6. 为2个快照运行差异并分析它。

基本上,分析应该从最大的正面差异开始,比如说对象类型,并找出导致这些额外对象粘在内存中的原因。

对于在多个线程中处理请求的Web应用程序来说,分析变得更加复杂,但仍然适用一般方法。

我做了很多专门用来减少应用程序内存占用的项目,而这个一般的方法,还有一些特定的应用程序调整和技巧。

这里的提问者,我不得不说,得到一个不需要5分钟回答任何点击的工具,使得找到潜在的内存泄漏更容易。

由于人们提出了一些工具(我只是在JDK和JProbe试用版中试过,所以我只是试过可视化的WM),但是我应该建议一个基于Eclipse平台的免费/开源工具,内存分析器(有时称为SAP内存分析仪)可在http://www.eclipse.org/mat/上找到; 。

这个工具最酷的地方在于,当我第一次打开堆转储索引时,它能够显示像保留堆这样的数据,而不用等待5分钟(对于每个对象来说,几乎所有的操作都比我尝试过的其他工具快得多) 。

当您打开转储时,第一个屏幕会显示一个饼图,其中包含最大的对象(计算保留的堆),并且可以快速导航到要获得较大舒适度的对象。 它也有一个查找可能的泄漏嫌疑人,我reccon可以派上用场,但由于导航对我来说是足够的,我没有真正进入它。

一个工具是一个很大的帮助。

然而,有时候你不能使用一个工具:堆转储是如此巨大的崩溃的工具,你正试图解决一个机器在某些生产环境,你只有壳牌访问等

在这种情况下,有助于了解hprof转储文件。

寻找SITES BEGIN。 这显示了什么对象正在使用最多的内存。 但是这些对象不是完全按照类型集合在一起的:每个条目还包括一个“跟踪”ID。 然后,您可以搜索“TRACE nnnn”来查看分配对象的堆栈的前几个帧。 通常,一旦我看到对象被分配的位置,我发现一个错误,我完成了。 此外,请注意,您可以使用-Xrunhprof选项控制堆栈中记录的帧数。

如果检出分配站点,并且没有发现任何错误,则必须从一些活动对象向根对象开始反向链接,以查找意外的引用链。 这是一个工具真正帮助的地方,但是你也可以手工完成同样的事情(用grep)。 不只有一个根对象(即,不被垃圾收集的对象)。 线程,类和堆栈框架作为根对象,强烈引用的任何东西都是不可收集的。

要执行链接,请在HEAP DUMP部分查找具有不良跟踪标识的条目。 这将带您到一个OBJ或ARR条目,它以十六进制显示唯一的对象标识符。 搜索该id的所有匹配项,以查找谁对该对象有强烈的引用。 沿着这些路径向后走,直到找出泄漏的位置。 看看为什么一个工具是如此方便?

静态成员是内存泄漏的重复犯罪者。 事实上,即使没有工具,花费几分钟时间查看静态地图成员的代码也是值得的。 地图可以变大吗? 有没有什么东西可以清理它的条目?

有些工具可以帮助您找到泄漏,例如JProbe,YourKit,AD4J或JRockit Mission Control。 最后一个是我个人最了解的。 任何好的工具都应该让您深入到可以轻松识别泄漏的位置,以及泄漏对象的分配位置。

使用HashTables,Hashmaps或类似的方法是你可以在Java中完全泄漏内存的几种方法之一。 如果我不得不手动找到泄漏,我会定期打印我的HashMap的大小,然后从那里找到添加项目的地方,忘记删除它们。

那么总是有一些低技术的解决方案,在你修改地图的时候添加地图大小的日志记录,然后在日志中搜索超出合理大小的地图。

大多数情况下,在企业应用程序中,给出的Java堆大于最大12到16 GB的理想大小。 我发现很难让NetBeans分析器直接在这些大的Java应用上工作。

但通常这是不需要的。 您可以使用jdk附带的jmap实用程序来执行“实时”堆转储,即在运行GC之后,jmap将转储堆。 对应用程序进行一些操作,等到操作完成后,再采取另一个“实时”堆转储。 使用像Eclipse MAT这样的工具来加载heapdump,在直方图上排序,查看哪些对象已经增加,哪些是最高的,这将提供一个线索。

 su proceeuser /bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process) 

这种方法只有一个问题。 巨大的堆转储,即使有现场选项,可能太大,不能转移到开发圈,可能需要一台具有足够内存/ RAM的机器打开。

这是类直方图进入图片的地方。 您可以使用jmap工具转储实时类直方图。 这将只给出内存使用的类直方图。基本上它不会有链接引用的信息。 例如,它可能会把字符数组放在顶部。 和String类在下面的某个地方。 你必须自己绘制连接。

 jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt 

取两个堆堆,取两个类直方图,就像上面描述的那样; 然后比较类的直方图,看看正在增加的类。 看看你是否可以将Java类与你的应用程序类联系起来。 这将提供一个很好的提示。 这是一个python脚本,可以帮助您比较两个jmap直方图转储。 histogramparser.py

最后,像JConolse和VisualVm这样的工具对于随着时间的推移看内存的增长是很重要的,并且看看是否有内存泄漏。 最后,有时你的问题可能不是内存泄漏,但内存使用率高。为此,启用GC日志记录;使用像G1GC更先进和新的压缩GC; 你可以使用像jstat这样的jdk工具来查看GC的行为

 jstat -gccause pid <optional time interval> 

其他refereces谷歌为-Jhat,jmap,Full GC,Humongous分配,G1GC

你真的需要使用跟踪分配的内存分析器。 看看JProfiler – 他们的“堆栈”功能非常好,并且与所有主要的Java IDE集成在一起。 这不是免费的,但它也不是那么昂贵(一个许可证是499美元) – 你会花费500美元的时间相当快速地努力找到漏洞与不太复杂的工具。

NetBeans有一个内置的分析器。

你可能想看看jconsole 。 这也是JDK的一部分,我发现它与jhat一起发现内存/引用泄漏很有帮助。 也看看这个博客条目。