如何找到Java内存泄漏

时间:2020-03-05 18:46:37  来源:igfitidea点击:

我们如何找到Java中的内存泄漏(例如使用JHat)?我试图在JHat中加载堆转储,以进行基本了解。但是,我不明白我应该如何找到根引用(ref)或者它的任何名称。基本上,我可以说哈希表条目有几百兆字节([java.util.HashMap $ Entry或者类似的东西),但是地图到处都用到了...有什么方法可以搜索大型地图,还是找到大对象树的一般根?

[编辑]
好的,到目前为止,我已经阅读了答案,但我们只能说我是个贱人(这意味着我对学习如何使用JHat而不是为JProfiler付费感兴趣)。另外,由于JHat是JDK的一部分,因此始终可用。除非当然不能使用JHat,否则只能使用蛮力,但我不敢相信这种情况。

另外,我认为我将无法进行实际修改(添加所有地图尺寸的记录)并运行足够长的时间,以至于我无法注意到泄漏。

解决方案

回答

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

回答

我们确实需要使用可跟踪分配的内存分析器。看看JProfiler,他们的"堆助行器"功能很棒,并且它们与所有主要的Java IDE集成在一起。它不是免费的,但也不是那么昂贵(单个许可证499美元),我们将很快花费500美元的时间,而这些时间很难用较不复杂的工具来查找泄漏。

回答

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

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

回答

NetBeans具有内置的探查器。

回答

工具是很大的帮助。

但是,有时我们无法使用工具:堆转储非常大,以至于使工具崩溃,我们正试图在某些只能通过shell访问的生产环境中对机器进行故障排除等。

在这种情况下,它有助于我们了解hprof转储文件的方式。

寻找SITES BEGIN。这向我们显示哪些对象正在使用最多的内存。但是对象并不是仅按类型组合在一起的:每个条目还包括一个"跟踪" ID。然后,我们可以搜索" TRACE nnnn"以查看分配对象的堆栈的前几帧。通常,一旦看到对象的分配位置,就会发现一个错误,然后就完成了。另外,请注意,我们可以使用-Xrunhprof选项控制堆栈中记录了多少帧。

如果我们检查了分配站点,但没有发现任何错误,则必须开始从某些活动对象到根对象的反向链接,以查找意外的参考链。这是工具真正提供帮助的地方,但是我们可以手工完成相同的操作(使用grep)。不仅有一个根对象(即不受垃圾回收的对象)。线程,类和堆栈框架充当根对象,它们强烈引用的任何内容均不可收集。

要进行链接,请在" HEAP DUMP"部分中查找具有错误跟踪ID的条目。这将带我们到OBJ或者ARR条目,该条目以十六进制显示唯一的对象标识符。搜索该id的所有出现,以查找谁对该对象有很强的引用。沿着这些路径中的每个路径向后分支,直到找出泄漏的位置。看看为什么工具这么方便?

静态成员是内存泄漏的重犯。实际上,即使没有工具,也值得花几分钟时间在代码中查找静态Map成员。地图可以变大吗?有没有清理过它的条目?

回答

我们可能想查看jconsole。它也是JDK的一部分,我发现与jhat一起查找内存/引用泄漏很有帮助。另请参阅此博客条目。

回答

我使用以下方法来查找Java中的内存泄漏。我使用jProfiler取得了巨大的成功,但是我相信任何具有图形功能的专业工具(差异更容易以图形形式进行分析)都可以使用。

  • 当所有初始化完成且应用程序处于空闲状态时,启动应用程序并等待其进入"稳定"状态。
  • 多次运行怀疑会导致内存泄漏的操作,以允许进行任何与数据库相关的高速缓存初始化。
  • 运行GC并获取内存快照。
  • 再次运行该操作。根据操作的复杂性和已处理数据的大小,可能需要运行几次到很多次。
  • 运行GC并获取内存快照。
  • 对2个快照运行差异并进行分析。

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

对于在多个线程中处理请求的Web应用程序,分析变得更加复杂,但是仍然可以使用通用方法。

我做了很多项目,目的是减少应用程序的内存占用,这种通用方法以及一些针对应用程序的调整和技巧总是很奏效。

回答

发问者在这里,我不得不说得到一种不需要5分钟即可回答任何点击的工具,这使得查找潜在的内存泄漏变得容易得多。

由于人们在建议使用几种工具(自从在JDK和JProbe试用版中获得该工具以来,我就只尝试使用Visual WM),尽管我应该建议在Eclipse平台上构建的免费/开源工具,即Memory Analyzer(有时也称为SAP内存)分析器),网址为http://www.eclipse.org/mat/。

这个工具真正很棒的地方是它在我第一次打开它时就索引了堆转储,这使它可以显示保留的堆之类的数据,而不必为每个对象等待5分钟(几乎所有操作都比我尝试过的其他工具快了很多) 。

当我们打开转储时,第一个屏幕将显示一个饼图,其中包含最大的对象(计算保留的堆),并且可以快速导航到较大的对象以增加舒适度。它还具有"发现可能泄漏的嫌疑犯",我认为可以派上用场,但是由于导航对我来说足够了,所以我没有真正涉足。