用于分析大型 Java 堆转储的工具

Posted

技术标签:

【中文标题】用于分析大型 Java 堆转储的工具【英文标题】:Tool for analyzing large Java heap dumps 【发布时间】:2011-08-31 07:49:15 【问题描述】:

我有一个想要分析的 HotSpot JVM 堆转储。 VM 使用-Xmx31g 运行,堆转储文件为 48 GB。

我什至不会尝试 jhat,因为它需要大约 5 倍的堆内存(在我的情况下是 240 GB)而且速度非常慢。 在分析堆转储数小时后,Eclipse MAT 崩溃并显示 ArrayIndexOutOfBoundsException

还有哪些其他工具可用于该任务?最好有一套命令行工具,其中包括一个将堆转储转换为有效数据结构以供分析的程序,以及其他几个处理预结构化数据的工具。

【问题讨论】:

您确定转储没有损坏并且您使用的是更新版本的 DTFJ JAR? ArrayIndexOutOfBoundsException 至少在 two bugs 中具有功能。我这么说是因为你还没有举报an OOME when running MAT, which has a different fix。 jhat 使用 heapMap 来存储读取的对象,它随着堆中存储的对象数量呈指数增长。一种选择是将 decl 从 heapMap 更改为 TreeMap,并运行 jhat 的堆大小至少与您的进程一样大。 我已经为 Eclipse MAT 的内存映射后端起草了一份提案,只要您有足够的本地磁盘可以溢出,它就可以让您处理比本地可用堆大得多的文件。欢迎反馈bugs.eclipse.org/bugs/show_bug.cgi?id=572512 @codeDr 我怀疑它是否呈指数增长。也许是二次的,那已经够糟糕了。 【参考方案1】:

通常,我使用的是 ParseHeapDump.sh 包含在 Eclipse Memory Analyzer 中并描述为 here,然后我在我们更强大的服务器上执行此操作(下载并复制到 linux .zip 发行版,在那里解压缩)。与从 GUI 解析堆相比,shell 脚本需要的资源更少,而且您可以在拥有更多资源的强大服务器上运行它(您可以通过在脚本的最后一行添加 -vmargs -Xmx40g -XX:-UseGCOverheadLimit 之类的内容来分配更多资源。 例如,该文件的最后一行在修改后可能如下所示

./MemoryAnalyzer -consolelog -application org.eclipse.mat.api.parse "$@" -vmargs -Xmx40g -XX:-UseGCOverheadLimit

./path/to/ParseHeapDump.sh ../today_heap_dump/jvm.hprof一样运行它

成功后,它会在 .hprof 文件旁边创建一些“索引”文件。

创建索引后,我尝试从中生成报告并将这些报告 scp 到我的本地计算机,并尝试查看是否可以仅凭此找到罪魁祸首(不仅仅是报告,而不是索引)。这是creating the reports的教程。

示例报告:

./ParseHeapDump.sh ../today_heap_dump/jvm.hprof org.eclipse.mat.api:suspects

其他报告选项:

org.eclipse.mat.api:overvieworg.eclipse.mat.api:top_components

如果这些报告还不够,并且如果我需要更多挖掘(例如,通过 oql),我将索引和 hprof 文件 scp 到我的本地计算机,然后打开堆转储(索引在与堆转储相同的目录)与我的 Eclipse MAT GUI。从那里开始,它不需要太多内存即可运行。

编辑: 我只是想添加两个注释:

据我所知,只有索引的生成是 Eclipse MAT 的内存密集型部分。获得索引后,您从 Eclipse MAT 进行的大部分处理都不需要那么多内存。 在 shell 脚本上执行此操作意味着我可以在无头服务器上执行此操作(我通常也在无头服务器上执行此操作,因为它们通常是最强大的服务器)。而且,如果您有一台可以生成该大小的堆转储的服务器,那么您很可能还有另一台服务器也可以处理这么多的堆转储。

【讨论】:

重要提示:ParseHeapDump.sh 仅与 Linux 版本一起打包,而不是 OSX 版本 -- eclipse.org/mat/downloads.php 当我尝试这个(ssh'd 在 linux 机器上 bash)时,它立即失败并显示“无法初始化 GTK+”。所以看起来(当前版本,2016-04-15)仍然认为它正在与 UI(?)交谈。 嗯,新版本的 ParseHeapDump.sh 想直接运行 ./MemoryAnalyzer。我正在尝试直接用 java 运行启动器,到目前为止这似乎正在工作,例如java -Xmx16g -Xms16g -jar plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar -consoleLog -consolelog -application org.eclipse.mat.api.parse "$@" 看来您可以通过下载 Linux 和 OSX 版本在 OS X 上使用它,然后将 ParseHeapDump.sh 复制到与 MemoryAnalyze 文件相同的目录(在我的情况下为 ~/Downloads/mat.app /Contents/MacOS) 并在那里修改和运行它。当然,或者通过 SSH 在某个远程服务器上运行它:) 使用 Eclipse 内存分析器 GUI 使用不超过 500MB 的内存打开了 2GB 堆转储。索引文件是在文件打开时动态创建的(耗时约 30 秒)。也许他们改进了这个工具。如果它真的这样工作,它比来回复制大文件更方便。即使没有任何控制台实用程序,内存占用量小对我来说也是一大优势。但老实说,我没有尝试非常大的转储(50+ GB)。非常有趣的是,使用此工具打开和分析如此大的转储需要多少内存。【参考方案2】:

第一步:增加分配给 MAT 的 RAM 量。默认不是很多,不能打开大文件。

如果在 MAC (OSX) 上使用 MAT,您将在 MemoryAnalyzer.app/Contents/MacOS 中拥有文件 MemoryAnalyzer.ini 文件。我对那个文件进行调整并让他们“接受”是行不通的。您可以改为基于此文件的内容创建修改后的启动命令/shell 脚本并从该目录运行它。就我而言,我想要 20 GB 堆:

./MemoryAnalyzer -vmargs -Xmx20g --XX:-UseGCOverheadLimit ... other params desired

只需通过终端从 Contents/MacOS 目录运行此命令/脚本,即可启动具有更多可用 RAM 的 GUI。

【讨论】:

谢谢。 DLd 今天的实用程序。尝试通过 2x-click 运行,它给出了一个错误。查看日志,无法创建数据文件并说使用开关。打开 .app 包,发现 MemoryAnalyzer.ini 在 Eclipse\ 文件夹中,而不是 \MacOS。啊哈!所以我在本地提取了所有文件并按照您的建议进行操作。我在 \MacOS 中创建了一个 .sh 文件,并将 Eclipse\MemoryAnalyzer.ini 中的命令作为单行移动到其中。保存的文件。在命令行上从 MacOS\ 运行 .sh 文件,瞧,它工作了。 真是一团糟。 MemoryAnalyzer.ini 不在应有的位置,即使您将其从 Eclipse 移至 MacOS,mod 也不会“占用”。所有这些都有助于推动 MAT 在尝试分析内存不足的 Java 堆时不会耗尽内存。我的 java hprof 是 1.7GB,我在 MacOS 10.15.7 Catalina 上运行。我不相信ini真的需要,不管你把它放在Mac上的什么地方。 Eclipse 文档有误。【参考方案3】:

这个相关问题的公认答案应该为您提供一个良好的开端(如果您可以访问正在运行的进程,生成实时 jmap 直方图而不是堆转储,它非常快):

Method for finding memory leak in large Java heap dumps

如果您期待一个不错的 GUI 工具,大多数其他堆分析器(我使用 IBM http://www.alphaworks.ibm.com/tech/heapanalyzer)至少需要比堆多一定百分比的 RAM。

除此之外,许多开发人员使用替代方法,例如实时堆栈分析来了解正在发生的事情。

虽然我必须质疑为什么你的堆这么大?对分配和垃圾收集的影响必须是巨大的。我敢打赌,堆中的大部分内容实际上应该存储在数据库/持久缓存等中。

【讨论】:

【参考方案4】:

我建议尝试 YourKit。它通常需要比堆转储大小少一点的内存(它索引它并使用该信息来检索您想要的内容)

【讨论】:

【参考方案5】:

Eclipse Memory Analyzer 的最新快照版本具有随机丢弃一定比例的对象以减少内存消耗并允许分析剩余对象的功能。请参阅 Bug 563960 和 nightly snapshot build 以测试此工具,然后再将其包含在 MAT 的下一个版本中。更新:它现在包含在已发布的 1.11.0 版本中。

【讨论】:

知道如何在没有 UI 的情况下做到这一点吗? 请参阅Batch mode 并提供以下选项:1. -discard_ratio=percentage。从大量转储中丢弃一小部分对象的选项。 2. -discard_pattern=正则表达式。与要丢弃的对象的类名匹配的正则表达式。 3. -discard_offset=偏移值。控制丢弃哪些特定对象。 4. -discard_seed=随机数生成器种子。控制丢弃哪些特定对象。【参考方案6】:

此人http://blog.ragozin.info/2015/02/programatic-heapdump-analysis.html

编写了一个自定义的“堆分析器”,它只是通过堆转储文件公开一个“查询样式”接口,而不是实际将文件加载到内存中。

https://github.com/aragozin/heaplib

虽然我不知道“查询语言”是否比此处接受的答案中提到的 eclipse OQL 更好。

【讨论】:

实际上在大转储上工作,不像github.com/on-site/fasthat。不错!【参考方案7】:

一个不太知名的工具 - http://dr-brenschede.de/bheapsampler/ 适用于大型堆。它通过采样工作,因此它不必阅读整个内容,虽然有点挑剔。

【讨论】:

不幸的是它说“常见问题:内存不足:将 -Xmx 增加到转储大小的 2/3”但我想如果你有足够的 RAM 或者可以在服务器上运行它够了,应该够了,谢谢!【参考方案8】:

这不是命令行解决方案,但我喜欢这些工具:

将堆转储复制到足以托管它的服务器。原服务器很有可能可以用。

通过ssh -X进入服务器远程运行图形工具,使用Java二进制目录下的jvisualvm加载堆转储的.hprof文件。

该工具不会一次将完整的堆转储加载到内存中,而是在需要时加载部分。当然,如果您在文件中环顾四周,所需的内存最终将达到堆转储的大小。

【讨论】:

【参考方案9】:

我遇到了一个有趣的工具,叫做 JXray。它提供有限的评估试用许可证。发现查找内存泄漏非常有用。你可以试一试。

【讨论】:

【参考方案10】:

尝试使用 jprofiler,它在分析大型 .hprof 时效果很好,我尝试过使用 22 GB 左右的文件。

https://www.ej-technologies.com/products/jprofiler/overview.html

499 美元/开发许可证,但有 10 天免费评估

【讨论】:

【参考方案11】:

当问题可以“轻松”重现时,一种未提及的替代方法是在内存增长到那么大之前进行堆转储(例如jmap -dump:format=b,file=heap.bin <pid>)。

在许多情况下,您无需等待 OOM 即可了解正在发生的事情。

此外,MAT 提供了比较不同快照的功能,可以派上用场(有关说明和说明,请参阅https://***.com/a/55926302/898154)。

【讨论】:

以上是关于用于分析大型 Java 堆转储的工具的主要内容,如果未能解决你的问题,请参考以下文章

深入理解Java虚拟机——虚拟机堆转储快照分析工具(jhat)

深入理解Java虚拟机——虚拟机堆转储快照分析工具(jhat)

在大型 Java 堆转储中查找内存泄漏的方法

创建和分析 Java 堆转储(Heap Dumps)

捕获系统堆转储数据关闭

Java堆转储在Google App引擎标准环境中?