Как анализировать Thread Dump
В программе курса Разработчик Java довольно много тем, посвященных внутренностям работы JVM. Мы разбираемся в механизмах работы коллекций, байт-кода, сборщика мусора и т.д. Сегодня предлагаем Вашему внимаю перевод довольно интересной статьи о thread dump-е. Что это такое, как его получить и как использовать.
Хотите узнать, как анализировать thread dump (дамп потоков)? Заходите под кат, чтобы узнать больше о том как в Java получить thread dump и что с ним потом делать.
Большинство современных Java-приложений являются многопоточными. Многопоточность может существенно расширить функционал приложения, в то же время она вносит существенную сложность.
В однопоточном приложении все ресурсы (разделяемая память, операции ввода/вывода и т.д.) могут использоваться без синхронизации, т.к. в любой момент времени только один поток пользуется ресурсом.
В случае многопоточных приложений необходимо найти компромисс между усложнением программы и возможным повышением производительности, когда несколько потоков могут использовать все доступные (часто больше одного) ядра центрального процессора (CPU). Если сделать все правильно, то используя многопоточность (формализована в Amdahl’s Law), можно добиться существенного прироста производительности приложения. Однако при этом надо помнить об обеспечении синхронного доступа нескольких потоков к разделяемому ресурсу. В большинстве случаев, фреймворки, такие как Spring, инкапсулируют работу с потоками и скрывают от пользователей многие технические детали. Однако и в случае применения современных сложных фреймворков что-то может пойти не так, и мы, как пользователи, столкнемся со сложно решаемыми багами многопоточности.
К счастью, Java оснащена специальным механизмом для получения информации о текущем состоянии всех потоков в любой момент времени — это thread dump (своего рода моментальный снимок). В этой статье мы изучим, как получить thread dump для приложения реалистичных размеров и как этот dump проанализировать.
Предполагается, что читатель владеет базовой информацией о многопоточном программировании и знает о проблемах синхронизации потоков и использовании совместных ресурсов. Тем не менее будет не лишним освежить в памяти некоторые основные термины и понятия.
Основная терминология
С первого взгляда Java thread dump-ы могут показаться «китайской грамотой», ключом к ее понимаю являются следующие понятия. В общем, давайте, повторим основные термины многопоточности, которые будем использовать для анализа дампов.
-
Thread или поток — дискретная единица многопоточности, управляемая Java Virtual Machine (JVM). Потоки JVM соответствуют потокам в операционной системе (OS) — native threads («естественные потоки»), которые и реализуют механизм выполнения кода.
У каждого потока есть уникальный идентификатор и имя. Потоки могут быть «демонами» и «не демонами».
Программа завершает свою работу, когда завершаются все потоки «не демоны» или вызывается метод Runtime.exit. Работающие «демоны» не влияют на завершение работы программы. Т.е. JVM ждем когда доработают все «не демоны» и завершает работу, на «не демонов» не обращает внимание.
За более подробной информацией обращайтесь к документации класса Thread.
Поток может находится в одном из следующих состояний:
- Alive thread или «живой» — поток, который выполняет некоторую работу (нормальное состояние).
- Blocked thread или «заблокированный» — поток, который попытался зайти в секцию синхронизации (synchronized), однако другой поток уже успел зайти в этот блок первым, и все следующие потоки, которые попытаются зайти в этот же блок оказываются заблокированными.
- Waiting thread или «ожидающий» — поток, который вызвал метод wait (возможно, с указанием таймаута) и сейчас ждет, когда другой метод выполнит notify или nonifyAll на этом же объекте.
Каждый объект в Java имеет монитор, при помощи которого поток может синхронизоваться, т.е. выставить блокировку, которая гарантирует, что ни один другой поток не получит доступ к этому объекту, пока блокировка не будет снята, т.е. поток — владелец блокировки не выйдет из блока synchronized.
Более детальную информацию можно найти в этих источниках:
Применяя эти простые понятия о потока в Java, мы можем создать тестовое приложение. Для этого приложения мы соберем thread dump. Полученный дамп проанализируем и извлечем полезную информацию о текущих потоках приложения.
Создание примера программы
Прежде, чем создать thread dump, нам надо разработать Java-приложение. Традиционный «hello, world!» для нашей цели слишком прост, а дамп среднего размера приложения может оказаться слишком сложным для демонстрации. Исходя из этого, мы создадим достаточно простое приложение, в котором создаются два потока. Причем потоки попадают в deadlock:
Эта программа создает два ресурса: resourceA и resourceB, и стартует два потока: threadLockingResourceAFirst и threadLockingResourceBFirst, которые блокируют ресурсы друг друга.
Причиной возникновения deadlock-а является «перекрестная» блокировка ресурсов потоками.
Причиной возникновения deadlock является попытка «взаимного» захвата ресурсов, т.е. поток threadLockingResourceAFirst захватывает ресурс resourceA, поток threadLockingResourceBFirst захватывает ресурс resourceB. После этого поток threadLockingResourceAFirst, не отпуская свой ресурс, пытается захватить resourceB, а поток threadLockingResourceBFirst, не отпуская свой ресурс, пытается захватить ресурс resourceA. В результате потоки блокируются. Задержка в 1с добавлена, чтобы гарантировать возникновение блокировки. Потоки ждут освобождение нужных ресурсов, но это никогда не случится.
Вывод программы будет таким (числа после java.lang.Object@ будут разные для каждого запуска):
После вывода этих сообщений программа будет выглядеть как работающая (процесс, выполняющий эту программу, не завершен), при этом программа не выполняет никакой работы. Вот так вот и выглядит deadlock на практике. Чтобы решить проблему, нам надо вручную создать tread dump и проанализировать состояние потоков.
Генерация Thread Dump
На практике, Java-программа может аварийно завершиться и при этом создать thread dump. Однако в ряде случаев (например в случае deadlock-ов), программа не завершается и thread dump не создает, она просто зависает. Для создания дампа таких зависших программ, прежде всего надо выяснить идентификатор процесса программы, т.е. Process ID (PID). Для этого можно воспользоваться утилитой JVM Process Status (JPS), которая начиная с версии 7, входит в состав Java Development Kit (JDK). Чтобы найти PID процесса нашей зависшей программы, мы просто выполним jps в терминале (Windows или Linux):
Первая колонка — это идентификатор локальной виртуальной машины (Local VM ID, т.е. lvmid) для выполняемого Java-процесса. В контексте локальной JVM, lvmid указывает на PID Java-процесса.
Надо отметить, что это значение, скорее всего, будет отличаться от значения выше. Вторая колонка — это имя приложения, которое может указывать на имя main-класса, jar-файла или быть равно «Unknown». Все зависит от того, как приложение было запущено.
В нашем случае имя приложения DeadlockProgram — это имя main-классы, который был запущен при старте программы. В примере выше PID программы 11568, этой информации достаточно для генерации thread dump’а. Для генерации дампа мы воспользуемся утилитой jstack, которая входит в состав JDK, начиная с версии 7. Чтобы получить дамп мы передадим в jstack в качестве параметра PID нашей программы и укажем флаг -l (создание длинного листинга). Вывод утилиты перенаправим в текстовый файл, т.е. thread_dump.txt:
Полученный файл thread_dump.txt содержит thread dump нашей зависшей программы и содержит важную информацию для диагностики причин возникновения deadlock-а.
Если используется JDK до 7 версии, то для генерации дампа можно воспользоваться утилитой Linux — kill с флагом -3. Вызов kill -3 отправит программе сигнал SIGQUIT.
В нашем случае вызов будет такой:
Анализ простого Thread Dump
Открыв файл thread_dump.txt, мы увидим примерно следующее содержание:
Introductory Information
Хотя на первый взгляд этот файл может показаться слишком сложным и запутанным, в действительности он весьма прост, если разбирать его по частям шаг за шагом.
В первой строке указывается время, когда дамп был сформирован, во второй — диагностическая информация о JVM, на которой дамп был получен:
В этой секции нет информации о потоках. Тут задается общий контекст системы, в которой был собран дамп.
Общие сведенья о потоках
В следующей секции представлена информация о потоках, которые выполнялись в системе в момент сбора дампа:
В следующей секции приводится список:
В нем содержится информация о потоках за пределами JVM, т.е. это не потоки виртуальной машины и не потоки сборщика мусора. Если посмотреть на адреса этих потоков, то можно заметить, что они соответствуют значению tid — «естественному, железному» (native) адресу в операционной системе, а не Thread ID.
Троеточия используются для сокрытия излишней информации:
Потоки
Сразу после блока SMR следует список потоков. Первый поток в нашем списке — Reference Handler:
Краткое описание потока
Состояние потока
Вторая строка — это текущее состояние потока. Возможные состояния потока приведены в enum:
Thread.State:
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
Более подробную информацию смотрите в документации.
Thread Stack Trace
Следующая секция содержит stack trace потока в момент снятия дампа. Этот stack trace очень похож на stack trace, который формируется не перехваченным исключением. И содержит имена классов и строк, которые выполнялись в момент формирования дампа. В случае потока Reference Handler мы не видим ничего интересного.
Однако в трассировке потока Thread-02 есть кое-что интересное, отличное от стандартного трейса:
В трассировке мы видим, что добавилась информация о блокировке. Этот поток ожидает блокировку на объекте с адресом 0x00000000894465b0 (тип объекта java.lang.Object). Более того поток сам удерживает блокировку с адресом 0x00000000894465a0 (тоже объект java.lang.Object). Эта информация нам пригодится далее для диагностики deadlock-а.
Захваченные примитивы синхронизации (Ownable Synchronizer)
В последней секции приводится список примитивов синхронизации (synchronizers), захваченных потоком. Это объекты, которые могут быть использованы для синхронизации потоков, например, защелки (locks).
В соответствии с официальной документацией Java, Ownable Synchronizer — это наследники AbstractOwnableSynchronizer (или его подкласса), которые могут быть эксклюзивно захвачены потоком для целей синхронизации.
ReentrantLock и write-lock, но не read-lock класса ReentrantReadWriteLock — два хороших примера таких «ownable synchronizers», предлагаемых платформой.
Для получения более подробной информации по этому вопросу можно обратиться к этому
посту.
Потоки JVM
В следующей секции дампа содержится информация о технических потоках JVM, которые не являются частью приложения и связаны с потоками операционной системы. Т.к. эти потоки работают вне приложения, у них нет идентификаторов потока. Чаще всего это потоки сборщика мусора и другие технические потоки JVM:
Глобальные ссылки JNI
В этой секции указывается количество глобальных ссылок, используемых JVM через JNI. Эти ссылки не обслуживаются сборщиком мусора и в определенных обстоятельствах могут стать причиной утечки памяти.
В большинстве простых случаев эта информация не используется. Однако важность глобальных ссылок надо понимать. Более подробную информацию смотрите в этом посте.
Взаимно заблокированные (Deadlocked) потоки
Последний раздел содержит информацию о найденных взаимных блокировках (deadlocks).
Если такие не обнаружатся, то и раздел будет пустым. Т.к. мы специально разработали приложение с блокировками, в нашем случае этот раздел есть. Блокировка обнаружена во время формирования дампа и представлена следующим сообщением:
В первом подразделе описывается сценарий взаимной блокировки (deadlock):
Поток Thread-0 ожидает возможность захватить монитор (это обращение к блоку synchronized(secondResource) в нашем приложении), в то же время этот поток удерживает монитор, который пытается захватить поток Thread-1 (это обращение к тому же фрагменту кода: synchronized(secondResource) в нашем приложении).
Эта циклическая блокировка по другому называется deadlock. На рисунке ниже
эта ситуация представлена в графическом виде:

Во втором подразделе для обоих заблокированных потоков приведен stack trace.
Этот stack trace позволяет нам проследить за работой каждого потока до появления блокировки.
В нашем случае, если мы посмотрим на строку:
at DeadlockProgram$DeadlockRunnable.run(DeadlockProgram.java:34), то увидим проблемный участок кода:
Эта строка является первой строкой блока synchronized, который является причиной блокировки, и подсказывает нам, что синхронизация на secondResource и является причиной взаимной блокировки. Чтобы исправить ситуацию, мы должны обеспечить в обоих потоках одинаковый порядок синхронизации на ресурсах resourceA и resourceB. Если мы сделаем это, то придем к следующему приложению:
Это приложение завершится без взаимной блокировки, и в качестве результата мы получим следующий вывод (обратите внимание на то, что адреса экземпляров класса Object изменились):
В результате, используя только информацию, полученную из thread dump, мы смогли найти причину и исправить взаимную блокировку в нашем приложении. Предложенная техника достаточна для большинства простых приложений (или приложений с небольшим количеством deadlock-ов). Чтобы разобраться с более сложными ситуациями, потребуются другие методы.
Анализ более сложных Thread Dump-ов
Дампы настоящих приложений могут быть очень большими и сложными.
В одной JVM одновременно могут быть запущены сотни тысяч потоков. И заблокированными могут оказаться больше чем два потока (или может быть несколько проблем многопоточности, вызванных одной проблемой).
Анализ такого громадного объема информации может стать настоящей проблемой.
Для анализа больших дампов предназначены специальные утилиты-анализаторы — Thread Dump Analyzers (TDAs). Эти утилиты парсят Java thread dump-ы и выводят информацию в человеко-читаемом виде, часто с применением графических средств. Более того, некоторые из них могут выполнить статический анализ и найти причину проблемы. Конечно, выбор конкретной утилиты зависит от целого ряда обстоятельств.
Тем не менее приведем список наиболее популярных TDA:
Заключение
Thread dump-ы — это отличное средство анализа состояния Java-приложения, особенно в случаях неожиданного поведения многопоточных приложений. Однако без надлежащего багажа знаний, дампы могут внести дополнительную сложность и в без того сложную ситуацию.
В этой статье мы разработали приложение с deadlock, сформировали дамп зависшего приложения. Проанализировали дамп и нашли причину блокировки и исправили её. Это не всегда так просто, для анализа большинства реальных приложений очень полезно использовать специальные утилиты — анализаторы.
Тем не менее, каждый профессиональный Java-разработчик должен понимать основы анализа thread dump-ов. Должен ориентироваться в их структуре, знать какую информацию можно извлечь и как ее использовать для решения проблем многопоточности.
Хотя, thread dump — это не «серебряная пуля» в мире многопоточности, тем не менее это важное средство диагностирования сложных, но довольно распространенных проблем многопоточных Java-приложений.
В программе курса Разработчик Java вопросы многопоточности занимают заметную часть. Мы детально рассматриваем как разрабатывать программы так, чтобы не приходилось по ночам разбираться с deadlock-в продакшене.
Как всегда интересны ваши мнения и комментарии, которые можно оставить тут или заглянуть к Виталию на день открытых дверей.
Extracting memory and thread dumps from a running JRE based JVM
![]()
Almost every Java developer knows about jmap and jstack tools that come with the JDK. These provide functionality to extract heap and thread information of a running JVM instance. Easy.
What if there’s a running JVM that has produced a deadlock and you want to take a thread dump while the process is running? You go in and run the following.
Turns out the system doesn’t know what jstack is. You don’t panic, but you get a tiny sensation at the back of your head saying you’re not leaving early this Friday.
What has happened is the running JVM is based on a JRE and not a JDK. The JRE is a minimal runtime that doesn’t pack the monitoring and analysis tools that the JDK packs.
So what are our options here?
- Stop the process. Download JDK, start the process again on top of JDK and hope the deadlock happens again. Nope.
- Start JVisualVM on your laptop and hope the process has JMX enabled. Nope.
- tools.jar TO THE RESCUE!
Functionalities such as jstack are implemented in the tools.jar file which is packed inside <JDK_HOME>/lib folder. We can use this to invoke the JStack class and get a thread dump of the running process.
So we march on to download and extract the JDK, and then to run the following.
..and come across the following error.
Darn it! Spoiled again!
How do we solve this? The above error is caused when the process can’t find libattach.so file which is related to the Dynamic Attach function related to JStack. Setting the following environment variable will help the JVM to find the libattach.so file.
Now let’s run JStack again, this time with results!
Now that we have the thread dump, we move on to the heap dump. The tool we normally use is jmap but that too is not available on the JRE. So what? We can use the binary in the JDK’s bin directory right? right?
Nope! Unless you match the JDK version with the exact version the JRE is at you get the above issue (which is pretty self-explanatory). So we download the JDK of the JRE of on top our process is running and run jmap again.
Now you go home, a proud developer who took the first dump out of the running server. And no that does not sound good on a different context.
What is Thread Dump and How to Analyze them?

Let’s talk about the thread dump, and how to analyze it.
We will also discuss how it helps to pinpoint the issues and some of the analyzer you can use.
What is Thread?
A process is a computer program which is loaded into the computer’s memory and is under execution. It can be executed by a processor or a set of processors. A process is described in memory with important information such as variable stores, file handles, the program counter, registers, and, signals, and so on.
A process can consist of many lightweight processes called threads. This helps to achieve parallelism wherein a process is divided into multiple threads. This results in better performance. All the threads within a process share the same memory space and are dependent on each other.
Thread Dumps
When the process is executing, we can detect the current state of execution of the threads in the process using thread dumps. A thread Dump contains a snapshot of all the threads active at a particular point during the execution of a program. It contains all relevant information about the thread and its current state.
A modern application today involves multiple numbers of threads. Each thread requires certain resources, performs certain activities related to the process. This can boost the performance of an application as threads can utilize available CPU cores.
But there’s are trade-offs, e.g., sometimes multiple threads may not coordinate well with each other and a deadlock situation may arise. So, if something goes wrong, we can use thread dumps to inspect the state of our threads.
Thread dump in Java
A JVM thread Dump is a listing of the state of all threads that are part of the process at that particular point of time. It contains information about the thread’s stack, presented as a stack trace. As it is written in plaintext, the contents can be saved for reviewing later. Analysis of thread dumps can help in
- Optimizing JVM performance
- Optimizing application performance
- Diagnosing problems, e.g. a deadlock, thread contention, etc.
Generation of Thread Dumps
There are many ways to generate thread dumps. Below are some JVM based tools and can be executed from the command line/terminal (CLI tools) or the /bin (GUI tools) directory of the installation folder of Java.
Let’s explore them.
#1. jStack
The simplest way to generate a thread dump is by using jStack. jStack ships with JVM and can be used from the command line. Here, we need the PID of the process for which we want to generate the thread dump. To get PID we can use jps command as shown below.
jps lists down all java process ids.
On Windows
On Linux
As we can see here, we get a list of all running java processes. It contains the local VM id for the running java process and the name of the application in columns one and two respectively. Now, to generate the thread dump, we use the jStack program with –l flag which creates a long listed output of the dump. We can also pipe the output to some text file of our choice.
jstack -l 26680<br>
#2. jvisualvm
Jvisualvm is a GUI tool that helps us troubleshoot, monitor, and profile Java applications. It also comes with JVM and can be launched from the /bin directory of our java installation. It is very intuitive and easy to use. Among other options, it also allows us to capture thread dump for a particular process.
To view the thread dump for a particular process, we can right-click on the program and select Thread Dump from the context menu.

#3. jcmd
JCMD is a command-line utility that ships with the JDK and are used to send diagnostic command requests to the JVM.
It however works only on the local machine where the Java application is running. It can be used to control Java Flight Recordings, diagnose and troubleshoot JVM and Java applications. We can use the Thread.print command of jcmd to get a list of thread dumps for a particular process specified by the PID.
Below is an example of how we can use jcmd .
jcmd 28036 Thread.print
#4. JMC
JMC stands for Java Mission Control. It is an open-source GUI tool that ships with JDK and is used to collect and analyze java application data.
It can be launched from the /bin folder of our Java installation. Java administrators and developers use the tool to gather detailed low-level information about the JVM’s and application’s behaviors. It enables detailed and efficient analysis of data collected by Java Flight Recorder.
On launching jmc , we can see list of java process which is running on the local machine. A remote connection is also possible. On a particular process, we can right click and choose Start Flight Recording and then check the thread dumps in the Threads tab.

#5. jconsole
jconsole is a Java Management Extension tool used for complaint management and monitoring.
It also has a set of predefined operations on the JMX agent which the user can perform. It enables the user in detecting and analyzing stack trace of a live program. It can be launched from the /bin folder of our Java installation.
Using the jconsole GUI tool we can inspect each thread’s stack trace when we connect it to a running java process. Then, in the Thread tab, we can see the name of all running threads. To detect a deadlock, we can click on the Detect Deadlock in the bottom right of the window. If a deadlock is detected it will appear in a new tab otherwise a No Deadlock Detected will be displayed.

#6. ThreadMxBean
ThreadMXBean is the interface for the management of the thread system of the Java virtual machine belonging to java.lang.Management package. It is mainly used to detect the threads which have entered a deadlock situation and get details about them.
We can use the ThreadMxBean interface to programmatically capture the thread dump. getThreadMXBean() method of ManagementFactory is used to get an instance of the ThreadMXBean interface. It returns the number of both daemon and non-daemon live threads. ManagementFactory is a factory class for getting the managed beans for the Java platform.
Manual Analysis of Thread Dumps
Analysis of thread dumps can be very useful in pinpointing issues in multithreaded processes. Issues such as deadlocks, lock contention, and excess CPU utilization by individual thread dumps can be resolved by visualizing the states of individual thread dumps.
Maximum throughput from the application can be achieved by rectifying the status of each thread after analyzing the thread dump.
For instance, let’s say, a process is using up a lot of CPU, we can find out if any thread is using the CPU the most. If there’s any such thread, we convert its LWP number to a hexadecimal number. Then from the thread dump, we can find the thread with nid equal to the previously obtained hexadecimal number. Using the stack trace of the thread we can pinpoint the issue. Let’s find out the process id of the thread using the below command.
ps -mo pid,lwp,stime,time,cpu -C java
Let’s have a look at below chunk of thread dump. To get thread dump for process 26680, use jstack -l 26680
Now, Let’s see what are the things we can explore using thread dumps. If we observe the thread dump, we can see a lot of content, which can be overwhelming. However, if we take one step at a time, it can be fairly simple to understand. Let’s understand the first line
2020-06-27 09:01:29
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
The above displays the time the dump was generated, and information about the JVM which was used. Next, in the end, we can see the list of threads, the first among them is our ReferenceHandler thread.
Analyzing Blocked Threads
If we analyze the below thread dump logs, we can find that it has detected threads with BLOCKED status which makes the performance of an application very slow. So, if we can find the BLOCKED threads, we can try to extract the threads related to the locks that the threads are trying to obtain. Analysis of the stack trace form the thread currently holding the lock can help in solving the problem.
Analyzing Deadlocked Thread
Another very commonly used application of thread dumps is the detection of deadlocks. The detection and solution of deadlocks can be a lot easier if we analyze the thread dumps.
A deadlock is a situation involving at least two threads where the resource required by one thread to continue execution is locked by another thread and at the same time, the resource required by the second thread is locked by the first thread.
So, none of the threads can continue execution, and this results in a deadlock situation and ends in the application getting stuck. If dreadlocks are present, then the final section of the thread dump will print out the information regarding the deadlock as follows.
Here we can see the deadlock information in a fairly human-readable format.
Other than this, if we sum up all the above chunk of thread dump together, then it states the below information.
- Reference handler is the human-readable name of the thread.
- #2 is the thread’s unique id.
- daemon denotes if the thread is a daemon thread.
- The numeric priority of the thread is given by prio=10.
- The current status of the thread is denoted by waiting on condition.
- Then we see the stack trace, which includes the locking information.
Thread Dumps Analyzers
Besides manual analysis, there are numerous tools available for analyzing thread dumps, both online and offline. Below are some of the listed tools, which we can use based on the requirements.
First, let’s explore online tools.
#1. Fast thread
Fast Thread is the DevOps engineer’s favorite thread dump analysis tool to troubleshoot complex production problems. This is an online Java thread dump analyzer, We can upload the thread dump as a file or we can directly copy and paste the thread dump.
Depending on the size, it will analyze the thread dump and displays the information as shown in the screenshot.

Features
- Troubleshoot JVM crashes, slowdowns, memory leaks, freezes, CPU Spikes
- Instant RCA (don’t wait for Vendors)
- Intuitive Dashboard
- REST API support
- Machine Learning
#2. Spotify Thread Dump Analyzer
The Spotify Thread Dump Analyzer is licensed under version 2.0 of the Apache license. It is an online tool and accepts the thread dump as a file or we can directly copy and paste the thread dump. Depending on the size, it will analyze the thread dump and displays the information as shown in the screenshot.

#3. Jstack review
Jstack.review analyzes java thread dumps from within the browser. This page is the client-side only.

#4. Site 24×7
This tool is a prerequisite for detecting faulty threads degrading Java Virtual Machine(JVM) performance. Issues such as deadlocks, lock contention, and excess CPU utilization by individual thread dumps can be resolved by visualizing the states of individual thread dumps.
Maximum throughput from the app can be achieved by rectifying the status of each thread provided by the tool.
Now, let’s explore offline tools.
When it comes to profiling, only the best tool is good enough.
#1. JProfiler
JProfiler is one of the most popular thread dump analyzers among Java developers. JProfiler’s intuitive UI helps you resolve performance bottlenecks, pin down memory leaks, and understand threading issues.

JProfiler supports profiling on the following platforms:
- Windows
- macOS
- Linux
- FreeBSD
- Solaris
- AIX
- HP-UX
Below are some features that make JProfiler the top choice for profiling our applications on the JVM.
Features
- Supports database profiling for JDBC, JPA, and NoSQL
- Support for Java enterprise edition is also available
- Presents high-level information about RMI calls
- Stellar analysis of memory leaks
- Extensive QA capabilities
- The integrated thread profiler is tightly integrated with the CPU profiling views.
- Support for platforms, IDE’s, and application servers.
#2. IBM TMDA
IBM Thread and Monitor Dump Analyzer for Java (TMDA) is a tool that allows identification of hangs, deadlocks, resource contention, and bottlenecks in Java thread dumps. It is an IBM product but the TMDA tool is provided as without any warranty or support; however, they try to fix and enhance the tool over time.

#3. ManageEngine
ManageEngine applications manager can help to monitor JVM Heap and Non-Heap memory. We can even configure thresholds and be alerted by email, SMS, etc, and ensure a Java application is tuned well.

#4. YourKit
YourKit consists of the below products called it as a Kit.
- Java Profiler – Fully featured low overhead profiler for Java EE and Java SE platforms.
- YouMonitor – Performance monitoring and profiling of Jenkins, TeamCity, Gradle, Maven, Ant, JUnit, and TestNG.
- .NET Profiler – Easy to use performance and memory profiler for .NET framework.
Conclusion
Now you know, how thread dumps are useful in understanding and diagnosing problems in multithreaded applications. With proper knowledge, regarding the thread dumps – their structure, the information contained in them, and so on – we can utilize them to identify the causes of the problems quickly.
How to get a thread and heap dump of a Java process on Windows that's not running in a console
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?
![]()
20 Answers 20
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
to get the heap for that process.
For systems where bash and pgrep are installed and a single Java process is running, try:
![]()
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
To take a thread dump in Unix, CTRL + C if your JVM is the foreground process or kill -3
With either platform, Java comes with several utilities that can help. For thread dumps, jstack
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.