JDK comes with a bunch of handy tools. It’s good to
know about them. In this post we will take a look at
jps is a JVM counterpart to unix
jps prints process PID and
the name of the main class
or the name of a jar file if the
application was started using
java -jar option.
But it can be more talkative.
-l option adds a package name to the
main class name and a full/relative path to the jar filename.
-m option will print command line arguments passed to the program.
To print JVM switches we use
jstack PID can be used to print current stack traces of
all threads running in java process.
You can also print stack traces from a core dump file.
The output of
jstack command is often referred to
as a thread dump.
Thread dumps are invaluable resources when it comes to debugging
nasty deadlocks that show up only on the production servers.
On the other hand the number of threads in a serious java application
can be overwhelming. To make the most of thread dumps, you
need to give threads meaningful names. You should give names
Thread::setName) at least to the threads that you create
you should also supply a “thread naming”
ThreadFactory when creating
new thread pools (e.g.
newFixedThreadPool(int nThreads, ThreadFactory threadFactory)).
Let’s create a simple app that deadlocks and see what
EDIT: I was tired when I wrote this code. It will deadlock
say 99% of time but not always. Instead of
sleep I should use
CountDownLatch. I leave the code as it is as I don’t want to regenerate
thread dumps but I wanted to point out this problem.
For readability I had to shorten
Notice that JVM was able to detect the deadlock, saving us a hours
of debugging. If you have a heisenbug you may consider running
jstack periodically and searching its output for
Found * deadlock lines.
Now let’s see how we can extract thread dumps for a core dump. And for that we need a core dump.
Here I will describe how to make a core dump on macOS 10.15
(this is based on this article)
First we need to execute
ulimit -c unlimited in the shell
to remove the file size limit on created core-dump files.
A simple crashing hello world C program can create about 2GB core dump,
Java cores can have sizes of 10GB or more.
Then we need to set appropriate
1777 is for sticky bit.
If a directory has this bit set then
only the owner of a file contained in that directory
can remove or rename that file.
If we additionally create a file with
then nobody beyond us will be able to change or
remove the file.
Then in the same shell in which we executed
ulimit -c unlimited
we have to run a java application and in a new
terminal window we need to send
SIGSEGV to that app:
After being hit by
SIGSEGV Java should crash with a message:
It may take a while to write 10GB+ file on disk so be patient.
Now for some reason I was not able to take a core dump from
official Oracle distribution of JDK. When I used OpenJDK
build everything worked perfectly. Now when I switched to OpenJDK
I have to use OpenJDKs
jstack to analyze the core dump.
For some reason in OpenJDK 14 the command
jstack /path/to/java coredump
did not work. Instead I have to use a new tool introduced in JDK9
jhsdb. Anyway the result is the same, we managed to
get thread dumps from the core dump. Again the tool was smart enough
to point out the deadlock (not visible on attached listing).
OK lets cleanup our system and revert the settings:
ulimit -c 0,
rm /cores/* and
sudo chmod 1775 /cores.
jmap can be used to display various info about
Java process heap. For example we may take a heap
histogram, which tells us number of instances and
total memory size taken per class.
But the real power of
jmap lies in its ability
to take heap dumps:
Heapdumps can then be comfortably opened and analyzed in tools like Eclipse Memory Analyzer.
Heapdumps can be quite huge, if you want to move them between servers remember to first compress them to speed things up. They also contain sensitive data like AWS access keys and user passwords, so please keep them secure.
TIP: You can also generate heapdumps on
out of memory errors using
-XX:+HeapDumpOnOutOfMemoryError JVM switch.
EDIT: Since JDK9 the recommended way of generating heapdumps changed. You may want to see this article on InfoQ.
Now what if you don’t want/have permissions to install fancy heapdump analyzers?
Not all is lost, we may still use primitive but working
jhat heapdump to start
jhat HTTP server with basic
jhat was removed in JDK9.