我有一个从控制台运行的Java应用程序,该应用程序反过来执行另一个Java进程。我想获得该子进程的线程/堆转储。

在Unix上,我可以执行kill -3 <pid>,但在Windows AFAIK上,获得线程转储的唯一方法是在控制台中按Ctrl-Break。但这只给了我父进程的转储,而不是子进程的转储。

有其他方法来获取堆转储吗?


当前回答

Visualvm跟踪:

如果你不能从jvisualvm连接到你正在运行的JVM,因为你没有使用正确的JVM参数启动它(并且它在远程框上),在远程框上运行jstatd,然后,假设你有一个直接连接,在visualvm中将它添加为“远程主机”,双击主机名,该框上的所有其他JVM将神奇地显示在visualvm中。

如果你没有“直接连接”到那个盒子上的端口,你也可以通过代理来做到这一点。

一旦你可以看到你想要的进程,在jvisualvm中钻到它,并使用monitor选项卡-> "heapdump"按钮。

其他回答

如果您使用的是JDK 1.6或以上版本,您可以使用jmap命令来获取Java进程的堆转储,条件是您应该知道ProcessID。

如果你在Windows机器上,你可以使用任务管理器来获取PID。对于Linux机器,您可以使用各种命令,如ps -A | grep java或netstat -tupln | grep java或top | grep java,这取决于您的应用程序。

然后可以使用类似jmap -dump:format=b,file=sample_heap_dump的命令。hprof 1234,其中1234是PID。

有多种工具可用于解释hprof文件。我将推荐使用简单的Oracle的visualvm工具。

如果你想在内存不足时进行堆转储,你可以使用-XX:-HeapDumpOnOutOfMemoryError选项启动Java

c.f. JVM选项参考页

您可以运行jconsole(包含在Java 6的SDK中),然后连接到Java应用程序。它将显示每个正在运行的线程及其堆栈跟踪。

您必须将输出从第二个java可执行文件重定向到某个文件。 然后,使用SendSignal向第二个进程发送“-3”。

为了从windows中的子java进程中获取线程转储/堆转储,首先需要确定子进程Id。

通过发出命令:jps,您将能够获得在您的windows计算机上运行的所有java进程id。您需要从该列表中选择子进程Id。一旦有了子进程Id,就可以使用各种选项来捕获线程转储和堆转储。

捕获线程转储:

有8个选项来捕获线程转储:

jstack 杀了3 jvisualVM 江铃汽车 Windows (Ctrl + Break) ThreadMXBean APM的工具 jcmd

关于每个选项的详细信息可以在本文中找到。有了捕获线程转储之后,可以使用fastThread、samurai等工具来分析线程转储。

捕获堆转储:

有7个选项可以捕获堆转储:

jmap - xx: + HeapDumpOnOutOfMemoryError jcmd JVisualVM JMX 编程方法 管理控制台

关于每个选项的详细信息可以在本文中找到。捕获堆转储之后,可以使用Eclipse内存分析工具HeapHero等工具来分析捕获的堆转储。