jcmd生成的堆转储文件在哪里创建?

9

我已经尝试使用jcmd(从git bash控制台窗口)进行堆转储:

$ /c/Program\ Files/Java/jdk1.8.0_202/bin/jcmd 25156 GC.heap_dump filename=livetest-grindtohalt.hprof
25156:
Heap dump file created

然而,该文件似乎不存在:

$ find -name livetest-grindtohalt.hprof

$

我应该在哪里找到它?


也许你应该在-name参数之前为你的查找命令指定一个路径。 - arkantos
find . -iname '*livetest-grindtohalt.hprof*' 也没有找到它。我假设它在当前目录下,因为这是运行jcmd命令和进程25156的代码库根目录。 - Robin Green
我理解并且觉得很有趣。如果不会耗尽你的机器资源,我会尝试使用 find / ... 命令。 - arkantos
3个回答

21

我也在Windows系统遇到了相同的问题。

jcmd 6232 GC.heap_dump filename=IShp1.hprof

运行时显示文件已创建,但在 C 盘搜索未找到。重新运行后得到“文件已存在”。

尝试使用指定的路径和不同的文件名。

jcmd 6232 GC.heap_dump filename=c:\temp\IShp2.hprof

这也出现了“文件已存在”的错误。

我得出结论:'filename'没有被正确使用。 可能 jcmd 正在将某个内部指定的未知文件名写入某个未知位置,而当指定了“文件名”时,它不起作用。

相反,

jcmd 6232 GC.heap_dump c:\temp\isHpdmp1.hprof

工作并将文件写入指定位置。因此,对于*nix系统,可能会像下面这样:

jcmd 6232 GC.heap_dump /opt/temp/myHd.hprof 

5
这个答案非常珍贵。实际上,“filename=”是一种文档错误。当您指定它时,jcmd会创建名为“filename”的转储文件,这就是为什么后续调用会产生“文件已存在”错误的原因(因为等号和其后面的所有内容都被忽略了)。正确的调用方式是直接给出所需的目标路径/名称,不需要“filename=”这部分。 - volkerk
能否将其输出到标准输出(stdout)?这样我们就可以通过scp进行流式传输。问题是,在现实场景中,服务器上的磁盘空间有时会过低,而在虚拟机上存储它并不是一个选项。 - zookastos
添加filename=abc.hprof会在Java进程的当前工作目录中创建一个名为“filename”的文件。 - Avinash Ganta

10
Douglas Kretzmann的回答为您提供了实用的jcmd使用方法。回答原帖中的问题,相对路径会根据指定Java进程的当前工作目录解析。因此,在执行过程中,应该在相对路径前加上正确的工作目录。
jcmd 6232 GC.heap_dump heap.hprof

您将能够在由输出的目录中找到heap.hprof

lsof -p 6232 | grep cwd

6

从实际情况看,上游已经拒绝在4年内“修复”诊断问题:

https://bugs.openjdk.java.net/browse/JDK-8177763 - 通过 jcmd 获取 hprof dump 应进行更强的选项检查。

官方文档 https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks004.html 提供了不正确的示例,例如:

Example 3-2 Create a Heap Dump using jcmd

jcmd <process id/main class> GC.heap_dump filename=Myheapdump

只需删除filename=

转储操作的当前工作目录是PID进程的目录,而不是jcmd的目录!因此,如果您不想搜索转储文件,请使用完整路径 )) 完整工作流程:

mkdir dest/
chmod a+w dest/

sudo jcmd
1234 my.evil.app

sudo -u myuser -g mygrp jcmd 1234 GC.heap_dump $PWD/dest/myapp.hprof

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接