如何在 Windows 上获取未在控制台中运行的 Java 进程的线程和堆转储

发布于 2024-07-10 17:29:10 字数 226 浏览 8 评论 0 原文

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

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

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

I have a Java application that I run from a console which in turn executes an another Java process. I want to get a thread/heap dump of that child process.

On Unix, I could do a kill -3 <pid> but on Windows AFAIK the only way to get a thread dump is Ctrl-Break in the console. But that only gives me the dump of the parent process, not the child.

Is there another way to get that heap dump?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

微暖i 2024-07-17 17:29:10

假设您知道 pid,您可以使用 jmap 获取任何正在运行的进程的转储。

使用任务管理器或资源监视器获取pid。 然后

jmap -dump:format=b,file=heap.hprof <pid>

获取该进程的堆。

对于安装了 bash 和 pgrep 且正在运行单个 Java 进程的系统,请尝试:

jmap -dump:format=b,file=heap.hprof $(pgrep java)

You can use jmap to get a dump of any process running, assuming you know the pid.

Use Task Manager or Resource Monitor to get the pid. Then

jmap -dump:format=b,file=heap.hprof <pid>

to get the heap for that process.

For systems where bash and pgrep are installed and a single Java process is running, try:

jmap -dump:format=b,file=heap.hprof $(pgrep java)
忆伤 2024-07-17 17:29:10

您混淆了两个不同的 java 转储。 kill -3 生成线程转储,而不是堆转储。

线程转储 = JVM 中每个线程的堆栈跟踪以文本形式输出到 stdout。

堆转储 = JVM 进程输出到二进制文件的内存内容。

要在 Windows 上进行线程转储,如果您的 JVM 是前台进程,则 CTRL+BREAK 是最简单的方法。 如果您在 Windows 上有类似 UNIX 的 shell,例如 Cygwin 或 MobaXterm,则可以像在 Unix 中一样使用 kill -3 {pid}

要在 Unix 中进行线程转储,如果您的 JVM 是前台进程,则 CTRL+Ckill -3 {pid} 都可以工作当您获得 JVM 的正确 PID 时。

对于任一平台,Java 都附带了几个可以提供帮助的实用程序。 对于线程转储,jstack {pid} 是您的最佳选择。 http://docs.oracle.com/javase/1.5 .0/docs/tooldocs/share/jstack.html

只是为了解决转储问题:堆转储并不常用,因为它们很难解释。 但是,如果您知道在哪里/如何查看它们,它们里面有很多有用的信息。 最常见的用途是定位内存泄漏。 最好在 java 命令行上设置 -D ,以便在发生 OutOfMemoryError 时自动生成堆转储,-XX:+HeapDumpOnOutOfMemoryError 但是,您也可以手动触发堆转储。 最常见的方法是使用 java 实用程序jmap

注意:此实用程序并非在所有平台上都可用。 从 JDK 1.6 开始,jmap 可在 Windows 上使用。

示例命令行看起来像

jmap -dump:file=myheap.bin {pid of the JVM}

输出“myheap.bin”不是人类可读的(对于我们大多数人来说),您将需要一个工具来分析它。 我的偏好是 MAT。 http://www.eclipse.org/mat/

You are confusing two different java dumps. kill -3 generates a thread dump, not a heap dump.

Thread dump = stack traces for each thread in the JVM output to stdout as text.

Heap dump = memory contents for the JVM process output to a binary file.

To take a thread dump on Windows, CTRL+BREAK if your JVM is the foreground process is the simplest way. If you have a unix-like shell on Windows like Cygwin or MobaXterm, you can use kill -3 {pid} like you can in Unix.

To take a thread dump in Unix, CTRL+C if your JVM is the foreground process or kill -3 {pid} will work as long as you get the right PID for the JVM.

With either platform, Java comes with several utilities that can help. For thread dumps, jstack {pid} is your best bet. http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html

Just to finish the dump question out: Heap dumps are not commonly used because they are difficult to interpret. But, they have a lot of useful information in them if you know where/how to look at them. The most common usage is to locate memory leaks. It is a good practice to set the -D on the java command-line so that the heap dump is generated automatically upon an OutOfMemoryError, -XX:+HeapDumpOnOutOfMemoryError But, you can manually trigger a heap dump, also. The most common way is to use the java utility jmap.

NOTE: this utility is not available on all platforms. As of JDK 1.6, jmap is available on Windows.

An example command-line would look something like

jmap -dump:file=myheap.bin {pid of the JVM}

The output "myheap.bin" is not human readable (for most of us), and you will need a tool to analyze it. My preference is MAT. http://www.eclipse.org/mat/

不再见 2024-07-17 17:29:10

我认为在 Linux 进程中创建 .hprof 文件的最佳方法是使用 jmap 命令。 例如:jmap -dump:format=b,file=filename.hprof {PID}

I think the best way to create .hprof file in Linux process is with jmap command. For example: jmap -dump:format=b,file=filename.hprof {PID}

絕版丫頭 2024-07-17 17:29:10

除了使用提到的 jconsole/visualvm 之外,您还可以在另一个命令行窗口上使用 jstack -l <​​vm-id> 并捕获该输出。

可以使用任务管理器(在 Windows 和 UNIX 上是进程 ID)或使用 jps 找到。

jstackjps 都包含在 Sun JDK 版本 6 及更高版本中。

In addition to using the mentioned jconsole/visualvm, you can use jstack -l <vm-id> on another command line window, and capture that output.

The <vm-id> can be found using the task manager (it is the process id on windows and unix), or using jps.

Both jstack and jps are include in the Sun JDK version 6 and higher.

谜兔 2024-07-17 17:29:10

我推荐随 JDK 一起发布的 Java VisualVM (jvisualvm.exe)。 它可以动态连接并访问线程和堆。 我发现它对于某些问题来说是无价的。

I recommend the Java VisualVM distributed with the JDK (jvisualvm.exe). It can connect dynamically and access the threads and heap. I have found in invaluable for some problems.

哀由 2024-07-17 17:29:10

如果您使用的是 server-jre 8 及更高版本,您可以使用以下命令:

jcmd PID GC.heap_dump /tmp/dump

If you are on server-jre 8 and above you can use this:

jcmd PID GC.heap_dump /tmp/dump
泪是无色的血 2024-07-17 17:29:10

如果您想要内存不足时的堆转储,可以使用选项 -XX:-HeapDumpOnOutOfMemoryError

cf JVM 选项参考页面

If you want a heapdump on out-of-memory, you can start Java with the option -XX:-HeapDumpOnOutOfMemoryError

c.f. JVM Options reference page

丿*梦醉红颜 2024-07-17 17:29:10

尝试以下选项之一。

  1. 对于 32 位 JVM:

    jmap -dump:format=b,file=;    
      
  2. 对于 64 位 JVM(显式引用):

    jmap -J-d64 -dump:format=b,file=;    
      
  3. 对于 VM 参数中具有 G1GC 算法的 64 位 JVM(仅使用 G1GC 算法生成活动对象堆):

    jmap -J-d64 -dump:live,format=b,file=;    
      

相关 SE 问题:jmap 命令的 Java 堆转储错误:过早 EOF

查看 jmap 的各种选项在这篇文章

Try one of below options.

  1. For 32 bit JVM:

    jmap -dump:format=b,file=<heap_dump_filename> <pid>
    
  2. For 64 bit JVM (explicitly quoting):

    jmap -J-d64 -dump:format=b,file=<heap_dump_filename> <pid>
    
  3. For 64 bit JVM with G1GC algorithm in VM parameters (Only live objects heap is generated with G1GC algorithm):

    jmap -J-d64 -dump:live,format=b,file=<heap_dump_filename> <pid>
    

Related SE question: Java heap dump error with jmap command : Premature EOF

Have a look at various options of jmap at this article

白芷 2024-07-17 17:29:10

您可以从 Cygwin 发送 kill -3 。 您必须使用 Cygwin ps 选项来查找 Windows 进程,然后将信号发送到该进程。

You can send the kill -3 <pid> from Cygwin. You have to use the Cygwin ps options to find windows processes then just send the signal to that process.

梦巷 2024-07-17 17:29:10

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

You could run jconsole (included with Java 6's SDK) then connect to your Java application. It will show you every Thread running and its stack trace.

不爱素颜 2024-07-17 17:29:10

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

You have to redirect output from second java executable to some file.
Then, use SendSignal to send "-3" to your second process.

时光沙漏 2024-07-17 17:29:10

如何获取java应用程序的进程id?

执行命令'jcmd'来获取java应用程序的进程id。

如何获取线程转储?

jcmd PID Thread.print > thread.dump

参考 链接

你甚至可以使用jstack来获取线程转储(jstack PID > thread.dump)。 参考链接

如何获取堆转储?

使用jmap工具获取堆转储。
jmap -F -dump:live,format=b,file=heap.bin PID

PID 代表应用程序的进程 ID。 参考链接

How to get process id of java application?

Execute the command 'jcmd' to get the process id of java applications.

How to get Thread dump?

jcmd PID Thread.print > thread.dump

Reference link

You can even use jstack to get thread dump (jstack PID > thread.dump). Reference link

How to get heap dump?

Use jmap tool to get heap dump.
jmap -F -dump:live,format=b,file=heap.bin PID

PID stands for process id of the application. Reference link

回首观望 2024-07-17 17:29:10

以下脚本使用 PsExec 连接到另一个 Windows 会话,因此即使通过远程桌面服务连接也能正常工作。

我为 Java 8 编写了一个小批处理脚本(使用 PsExecjcmd) 名为 jvmdump.bat,它转储线程、堆、系统属性和 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 会话中运行,因此,如果您通过远程桌面连接,则可能需要在 Session 0 中启动命令提示符并从那里运行它。 例如,

%PsExec% -s -h -d -i 0 cmd.exe

这将提示您(单击底部的任务栏图标)在交互式会话中查看消息,这将带您进入另一个会话中的新控制台,您可以从中运行jvmdump.bat 脚本。

The following script uses PsExec to connect to another Windows Session so it works even when connected via Remote Desktop Service.

I wrote a small batch script for Java 8 (using PsExec and jcmd) named jvmdump.bat, which dumps the threads, heap, system properties, and JVM args.

:: 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%

It must be run in the same Windows session of the user that started the JVM, so if you connect through Remote Desktop you might need to launch a command prompt in Session 0 and run it from there. e.g.

%PsExec% -s -h -d -i 0 cmd.exe

This will prompt you (click the taskbar icon at the bottom) to View the message in the interactive session, which will take you to the new console in the other session from which you can run the jvmdump.bat script.

是伱的 2024-07-17 17:29:10

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

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

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

有多种工具可用于解释 hprof 文件。 我会推荐Oracle的visualvm工具,使用起来很简单。

If you are using JDK 1.6 or above, You can use jmap command to take a heap Dump of a Java process, condition is you should known ProcessID.

If you are on Windows Machine, you can use Task Manager to get PID. For Linux machine you can use varieties of command like ps -A | grep java or netstat -tupln | grep java or top | grep java, depends on your application.

Then you can use the command like jmap -dump:format=b,file=sample_heap_dump.hprof 1234 where 1234 is PID.

There are varieties of tool available to interpret the hprof file. I will recommend Oracle's visualvm tool, which is simple to use.

丶视觉 2024-07-17 17:29:10

如果由于某种原因您不能(或不想)使用控制台/终端,还有一个替代解决方案。 您可以让 Java 应用程序为您打印线程转储。 收集堆栈跟踪的代码相当简单,可以附加到按钮或 Web 界面。

private static String getThreadDump() {
    Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

    StringBuilder out = new StringBuilder();
    for (Map.Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) {
        Thread thread = entry.getKey();
        StackTraceElement[] elements = entry.getValue();
        out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
        out.append('\n');

        for (StackTraceElement element : elements) {
            out.append(element.toString()).append('\n');
        }
        out.append('\n');
    }
    return out.toString();
}

此方法将返回一个如下所示的字符串:

main | prio=5 | RUNNABLE
java.lang.Thread.dumpThreads(Native Method)
java.lang.Thread.getAllStackTraces(Thread.java:1607)
Main.getThreadDump(Main.java:8)
Main.main(Main.java:36)

Monitor Ctrl-Break | prio=5 | RUNNABLE
java.net.PlainSocketImpl.initProto(Native Method)
java.net.PlainSocketImpl.<clinit>(PlainSocketImpl.java:45)
java.net.Socket.setImpl(Socket.java:503)
java.net.Socket.<init>(Socket.java:424)
java.net.Socket.<init>(Socket.java:211)
com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:59)

Finalizer | prio=8 | WAITING
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

Reference Handler | prio=10 | WAITING
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:502)
java.lang.ref.Reference.tryHandlePending(Reference.java:191)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

对于那些对带有流的 Java 8 版本感兴趣的人,代码更加紧凑:

private static String getThreadDump() {
    Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
    StringBuilder out = new StringBuilder();
    allStackTraces.forEach((thread, elements) -> {
        out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
        out.append('\n');

        Arrays.stream(elements).forEach(element -> out.append(element.toString()).append('\n'));
        out.append('\n');
    });
    return out.toString();
}

您可以使用以下命令轻松测试此代码:

System.out.print(getThreadDump());

If you can't (or don't want) to use the console/terminal for some reason, there is an alternative solution. You can make the Java application print the thread dump for you. The code that collects the Stack Trace is reasonable simple and can be attached to a button or a web interface.

private static String getThreadDump() {
    Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

    StringBuilder out = new StringBuilder();
    for (Map.Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) {
        Thread thread = entry.getKey();
        StackTraceElement[] elements = entry.getValue();
        out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
        out.append('\n');

        for (StackTraceElement element : elements) {
            out.append(element.toString()).append('\n');
        }
        out.append('\n');
    }
    return out.toString();
}

This method will return a string that looks like this:

main | prio=5 | RUNNABLE
java.lang.Thread.dumpThreads(Native Method)
java.lang.Thread.getAllStackTraces(Thread.java:1607)
Main.getThreadDump(Main.java:8)
Main.main(Main.java:36)

Monitor Ctrl-Break | prio=5 | RUNNABLE
java.net.PlainSocketImpl.initProto(Native Method)
java.net.PlainSocketImpl.<clinit>(PlainSocketImpl.java:45)
java.net.Socket.setImpl(Socket.java:503)
java.net.Socket.<init>(Socket.java:424)
java.net.Socket.<init>(Socket.java:211)
com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:59)

Finalizer | prio=8 | WAITING
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

Reference Handler | prio=10 | WAITING
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:502)
java.lang.ref.Reference.tryHandlePending(Reference.java:191)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

For those interested in a Java 8 version with streams, the code is even more compact:

private static String getThreadDump() {
    Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
    StringBuilder out = new StringBuilder();
    allStackTraces.forEach((thread, elements) -> {
        out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
        out.append('\n');

        Arrays.stream(elements).forEach(element -> out.append(element.toString()).append('\n'));
        out.append('\n');
    });
    return out.toString();
}

You can easily test this code with:

System.out.print(getThreadDump());
つ可否回来 2024-07-17 17:29:10

为了从 Windows 中的子 java 进程获取线程转储/堆转储,您需要首先识别子进程 ID。

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

捕获线程转储:

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

  1. jstack
  2. Kill -3
  3. jvisualVM
  4. JMC
  5. Windows (Ctrl + Break)
  6. ThreadMXBean
  7. APM Tools
  8. jcmd

有关每个选项的详细信息,请参阅 本文。 捕获线程转储后,您可以使用 fastThreadSamuraito 分析线程转储。

捕获堆转储:

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

  1. jmap

  2. -XX:+HeapDumpOnOutOfMemoryError

  3. jcmd

  4. JVisualVM

  5. JMX

  6. 编程方法

  7. 管理控制台

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

Inorder to take thread dump/heap dump from a child java process in windows, you need to identify the child process Id as first step.

By issuing the command: jps you will be able get all java process Ids that are running on your windows machine. From this list you need to select child process Id. Once you have child process Id, there are various options to capture thread dump and heap dumps.

Capturing Thread Dumps:

There are 8 options to capture thread dumps:

  1. jstack
  2. kill -3
  3. jvisualVM
  4. JMC
  5. Windows (Ctrl + Break)
  6. ThreadMXBean
  7. APM Tools
  8. jcmd

Details about each option can be found in this article. Once you have capture thread dumps, you can use tools like fastThread, Samuraito analyze thread dumps.

Capturing Heap Dumps:

There are 7 options to capture heap dumps:

  1. jmap

  2. -XX:+HeapDumpOnOutOfMemoryError

  3. jcmd

  4. JVisualVM

  5. JMX

  6. Programmatic Approach

  7. Administrative consoles

Details about each option can be found in this article. Once you have captured heap dump, you may use tools like Eclipse Memory Analysis tool, HeapHero to analyze the captured heap dumps.

同展鸳鸯锦 2024-07-17 17:29:10

也许jcmd

Jcmd 实用程序用于向 JVM 发送诊断命令请求,这些请求对于控制 Java 飞行记录、排除故障以及诊断 JVM 和 Java 应用程序非常有用。

jcmd 工具是随 Oracle Java 7 一起引入的,通过使用它来识别 Java 进程的 ID(类似于 jps)、获取堆转储(类似于 jmap)、获取线程转储(类似于 jstack),在解决 JVM 应用程序问题时特别有用。 ),查看虚拟机特征,例如系统属性和命令行标志(类似于 jinfo),以及获取垃圾收集统计信息(类似于 jstat)。 jcmd 工具被称为“用于调查和解决 JVM 应用程序问题的瑞士军刀”和“隐藏的宝石”。

以下是调用 jcmd 时需要使用的流程:

  1. 转到 jcmd GC.heap_dump
  2. 其中
  3. pid: 是一个 Java 进程 ID,将为其捕获堆转储 另外,
  4. file-path: 是打印堆转储的文件路径。

查看有关获取 Java 堆转储 的更多信息。

Maybe jcmd?

Jcmd utility is used to send diagnostic command requests to the JVM, where these requests are useful for controlling Java Flight Recordings, troubleshoot, and diagnose JVM and Java Applications.

The jcmd tool was introduced with Oracle's Java 7 and is particularly useful in troubleshooting issues with JVM applications by using it to identify Java processes' IDs (akin to jps), acquiring heap dumps (akin to jmap), acquiring thread dumps (akin to jstack), viewing virtual machine characteristics such as system properties and command-line flags (akin to jinfo), and acquiring garbage collection statistics (akin to jstat). The jcmd tool has been called "a swiss-army knife for investigating and resolving issues with your JVM application" and a "hidden gem."

Here’s the process you’ll need to use in invoking the jcmd:

  1. Go to jcmd <pid> GC.heap_dump <file-path>
  2. In which
  3. pid: is a Java Process Id, for which the heap dump will be captured Also, the
  4. file-path: is a file path in which the heap dump is be printed.

Check it out for more information about taking Java heap dump.

<逆流佳人身旁 2024-07-17 17:29:10

下面的java代码用于通过提供远程进程的PID来获取Java进程的堆转储。 该程序使用远程 JMX 连接将堆转储到文件。 这可能对某些人有帮助。 不需要 jmap。

import java.lang.management.ManagementFactory;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.reflect.Method;

public class HeapDumper {

public static final String HOST = "192.168.11.177";
public static final String PORT = "1600";
public static final String FILE_NAME = "heapDump.hprof";
public static final String FOLDER_PATH = "C:/";
private static final String HOTSPOT_BEAN_NAME ="com.sun.management:type=HotSpotDiagnostic";

public static void main(String[] args) {
    if(args.length == 0) {
        System.out.println("Enter PID of the Java Process !!!");
        return;
    }
    
    String pidString = args[0];
    int pid = -1;
    if(pidString!=null && pidString.length() > 0) {
        try {
            pid = Integer.parseInt(pidString);
        }
        catch(Exception e) {
            System.out.println("PID is not Valid !!!");
            return;
        }
    }
    boolean isHeapDumpSuccess = false;
    boolean live = true;
    if(pid > 0) {
        MBeanServerConnection beanServerConn = getJMXConnection();
        
        if(beanServerConn!=null) {
            Class clazz = null;
            String dumpFile = FOLDER_PATH+"/"+FILE_NAME;
            try{
                clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
                Object hotspotMBean = ManagementFactory.newPlatformMXBeanProxy(beanServerConn, HOTSPOT_BEAN_NAME, clazz);
                Method method = clazz.getMethod("dumpHeap", new Class[]{String.class , boolean.class});
                method.setAccessible(true);
                method.invoke(hotspotMBean , new Object[] {dumpFile, new Boolean(live)});
                isHeapDumpSuccess = true;
            }
            catch(Exception e){
                e.printStackTrace();
                isHeapDumpSuccess = false;
            }
            finally{
                clazz = null;
            }
        }
    }
    
    if(isHeapDumpSuccess){
        System.out.println("HeapDump is Success !!!");
    }
    else{
        System.out.println("HeapDump is not Success !!!");
    }
}

private static MBeanServerConnection getJMXConnection() {
    MBeanServerConnection mbeanServerConnection = null;
    String urlString = "service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi";
    try {
        JMXServiceURL url = new JMXServiceURL(urlString);
        JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
        mbeanServerConnection = jmxConnector.getMBeanServerConnection();
        System.out.println("JMX Connection is Success for the URL :"+urlString);
    }
    catch(Exception e) {
        System.out.println("JMX Connection Failed !!!");
    }
    return mbeanServerConnection;
}

}

Below java code is used to get the Heap Dump of a Java Process by providing a remote process' PID. The Program uses Remote JMX connection to dump heap to a file. It may be helpful for some one. Doesn't require jmap.

import java.lang.management.ManagementFactory;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.reflect.Method;

public class HeapDumper {

public static final String HOST = "192.168.11.177";
public static final String PORT = "1600";
public static final String FILE_NAME = "heapDump.hprof";
public static final String FOLDER_PATH = "C:/";
private static final String HOTSPOT_BEAN_NAME ="com.sun.management:type=HotSpotDiagnostic";

public static void main(String[] args) {
    if(args.length == 0) {
        System.out.println("Enter PID of the Java Process !!!");
        return;
    }
    
    String pidString = args[0];
    int pid = -1;
    if(pidString!=null && pidString.length() > 0) {
        try {
            pid = Integer.parseInt(pidString);
        }
        catch(Exception e) {
            System.out.println("PID is not Valid !!!");
            return;
        }
    }
    boolean isHeapDumpSuccess = false;
    boolean live = true;
    if(pid > 0) {
        MBeanServerConnection beanServerConn = getJMXConnection();
        
        if(beanServerConn!=null) {
            Class clazz = null;
            String dumpFile = FOLDER_PATH+"/"+FILE_NAME;
            try{
                clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
                Object hotspotMBean = ManagementFactory.newPlatformMXBeanProxy(beanServerConn, HOTSPOT_BEAN_NAME, clazz);
                Method method = clazz.getMethod("dumpHeap", new Class[]{String.class , boolean.class});
                method.setAccessible(true);
                method.invoke(hotspotMBean , new Object[] {dumpFile, new Boolean(live)});
                isHeapDumpSuccess = true;
            }
            catch(Exception e){
                e.printStackTrace();
                isHeapDumpSuccess = false;
            }
            finally{
                clazz = null;
            }
        }
    }
    
    if(isHeapDumpSuccess){
        System.out.println("HeapDump is Success !!!");
    }
    else{
        System.out.println("HeapDump is not Success !!!");
    }
}

private static MBeanServerConnection getJMXConnection() {
    MBeanServerConnection mbeanServerConnection = null;
    String urlString = "service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi";
    try {
        JMXServiceURL url = new JMXServiceURL(urlString);
        JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
        mbeanServerConnection = jmxConnector.getMBeanServerConnection();
        System.out.println("JMX Connection is Success for the URL :"+urlString);
    }
    catch(Exception e) {
        System.out.println("JMX Connection Failed !!!");
    }
    return mbeanServerConnection;
}

}

英雄似剑 2024-07-17 17:29:10

Visualvm 后续:

如果由于没有使用正确的 JVM 参数启动它(并且它位于远程机器上),因此无法从 jvisualvm“连接”到正在运行的 JVM,请在远程机器上运行 jstatd ,然后,假设您有直接连接,将其添加为 VisualVM 中的“远程主机”,双击主机名,该框中的所有其他 JVM 将神奇地显示在 VisualVM 中。

如果您没有到该盒子上的端口的“直接连接”,您也可以通过 代理

一旦您可以看到所需的进程,请在 jvisualvm 中深入研究它并使用“监视器”选项卡 ->; “堆转储”按钮。

Visualvm followup:

If you "can't connect" to your running JVM from jvisualvm because you didn't start it with the right JVM arguments (and it's on remote box), run jstatd on the remote box, then, assuming you have a direct connection, add it as a "remote host" in visualvm, double click the host name, and all other JVM's on that box will magically show up in visualvm.

If you don't have "direct connection" to ports on that box, you can also do this through a proxy.

Once you can see the process you want, drill into it in jvisualvm and use monitor tab -> "heapdump" button.

献世佛 2024-07-17 17:29:10

在 Oracle JDK 上,我们有一个名为 jmap 的命令(可在 Java Home 的 bin 文件夹中找到)。
命令的用法如下

jmap(选项)(pid)

示例:jmap -dump:live,format=b,file=heap.bin (pid)

On a Oracle JDK, we have a command called jmap (available in the bin folder of Java Home).
usage of the command comes as follows

jmap (option) (pid)

Example: jmap -dump:live,format=b,file=heap.bin (pid)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文