我有一个从控制台运行的Java应用程序,该应用程序反过来执行另一个Java进程。我想获得该子进程的线程/堆转储。
在Unix上,我可以执行kill -3 <pid>,但在Windows AFAIK上,获得线程转储的唯一方法是在控制台中按Ctrl-Break。但这只给了我父进程的转储,而不是子进程的转储。
有其他方法来获取堆转储吗?
我有一个从控制台运行的Java应用程序,该应用程序反过来执行另一个Java进程。我想获得该子进程的线程/堆转储。
在Unix上,我可以执行kill -3 <pid>,但在Windows AFAIK上,获得线程转储的唯一方法是在控制台中按Ctrl-Break。但这只给了我父进程的转储,而不是子进程的转储。
有其他方法来获取堆转储吗?
当前回答
下面的脚本使用PsExec连接到另一个Windows会话,因此即使通过远程桌面服务连接,它也能工作。
我为Java 8编写了一个名为jvmdump.bat的小批处理脚本(使用PsExec和jcmd),它可以转储线程、堆、系统属性和JVM参数。
:: set the paths for your environment
set PsExec=C:\Apps\SysInternals\PsExec.exe
set JAVA_HOME=C:\Apps\Java\jdk1.8.0_121
set DUMP_DIR=C:\temp
@echo off
set PID=%1
if "%PID%"=="" (
echo usage: jvmdump.bat {pid}
exit /b
)
for /f "tokens=2,3,4 delims=/ " %%f in ('date /t') do set timestamp_d=%%h%%g%%f
for /f "tokens=1,2 delims=: " %%f in ('time /t') do set timestamp_t=%%f%%g
set timestamp=%timestamp_d%%timestamp_t%
echo datetime is: %timestamp%
echo ### Version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Command >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.command_line >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.system_properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% Thread.print -l >"%DUMP_DIR%\%PID%-%timestamp%-threads.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% GC.heap_dump "%DUMP_DIR%\%PID%-%timestamp%-heap.hprof"
echo Dumped to %DUMP_DIR%
它必须在启动JVM的用户的同一个Windows会话中运行,因此如果您通过远程桌面连接,您可能需要在会话0中启动命令提示符并从那里运行它。如。
%PsExec% -s -h -d -i 0 cmd.exe
这将提示您(单击底部的任务栏图标)查看交互式会话中的消息,这将把您带到另一个会话中的新控制台,从中可以运行jvmdump.bat脚本。
其他回答
您必须将输出从第二个java可执行文件重定向到某个文件。 然后,使用SendSignal向第二个进程发送“-3”。
试试下面的一种选择。
对于32位JVM: Jmap -dump:format=b,file=<heap_dump_filename> <pid> 64位JVM(显式引用): jmap -J-d64 -dump:format=b,file=<heap_dump_filename> <pid> 对于64位JVM,在VM参数中使用G1GC算法(仅使用G1GC算法生成活对象堆): jmap -J-d64 -dump:live,format=b,file=<heap_dump_filename> <pid>
相关SE问题:Java堆转储错误与jmap命令:过早的EOF
看看本文中jmap的各种选项
如果你在服务器-jre 8及以上,你可以使用这个:
jcmd PID GC.heap_dump /tmp/dump
除了使用上面提到的jconsole/visualvm之外,您还可以在另一个命令行窗口上使用jstack -l <vm-id>,并捕获输出。
<vm-id>可以使用任务管理器(它是windows和unix上的进程id)或使用jps找到。
jstack和jps都包含在Sun JDK版本6及更高版本中。
如何获取java应用程序的进程id ?
执行“jcmd”命令可获取java应用程序的进程id。
如何获得线程转储?
jcmd PID线程。打印>线程
参考链接
您甚至可以使用jstack来获取线程转储(jstack PID > thread.dump)。参考链接
如何获得堆转储?
使用jmap工具获取堆转储。 jmap -F -dump:live,format=b,file=heap.bin PID
PID:应用程序的进程号。参考链接