jvm generate - How to get a thread and heap dump of a Java process on Windows that's not running in a console




linux analyzer (13)

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?


Answers

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.


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/


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.


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

jcmd PID GC.heap_dump /tmp/dump

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


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

c.f. JVM Options reference page


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());

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


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)


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}


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.


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=cheap.bin <pid>

to get the heap for that process.


How to take heap dump in Sun JDK 1.5 (windows) programmatically

There are many options to take heap dump in JDK 5. See

Try as much as you can.





java jvm heap-dump thread-dump