1. Обзор
В этом руководстве мы обсудим различные способы захвата дампа потока приложения Java.
Дамп потока — это моментальный снимок состояния всех потоков процесса Java . Состояние каждого потока представлено трассировкой стека, показывающей содержимое стека потока. Дамп потока полезен для диагностики проблем, так как он отображает активность потока. Дампы потоков записываются в виде обычного текста, поэтому мы можем сохранить их содержимое в файл и просмотреть их позже в текстовом редакторе .
В следующих разделах мы рассмотрим несколько инструментов и подходов к созданию дампа потока.
2. Использование утилит JDK
JDK предоставляет несколько утилит, которые могут записывать дамп потока Java-приложения. Все утилиты расположены в папке bin
внутри домашнего каталога JDK . Поэтому мы можем запускать эти утилиты из командной строки, пока этот каталог находится в нашем системном пути.
2.1. jstack
jstack — это утилита JDK командной строки, которую мы можем использовать для захвата дампа потока. Он берет pid
процесса и отображает дамп потока в консоли. В качестве альтернативы мы можем перенаправить его вывод в файл.
Давайте взглянем на основной синтаксис команды для захвата дампа потока с помощью jstack:
jstack [-F] [-l] [-m] <pid>
Все флаги необязательны. Давайте посмотрим, что они означают:
Опция -F принудительно
создает дамп потока; удобно использовать, когдаjstack pid
не отвечает (процесс завис)Опция -l
указывает утилите искать доступные синхронизаторы в куче и блокироватьПараметр -m
печатает собственные кадры стека (C и C++) в дополнение к кадрам стека Java.
Давайте воспользуемся этим знанием, захватив дамп потока и перенаправив результат в файл:
jstack 17264 > /tmp/threaddump.txt
Помните, что мы можем легко получить pid
процесса Java с помощью команды jps
.
2.2. Управление полетами Java
Java Mission Control (JMC) — это инструмент с графическим интерфейсом, который собирает и анализирует данные из приложений Java. После запуска JMC отображает список процессов Java, запущенных на локальной машине. Мы также можем подключаться к удаленным процессам Java через JMC.
Мы можем щелкнуть правой кнопкой мыши по процессу и выбрать опцию « Начать запись полета ».
После этого на вкладке Threads
отображаются дампы потоков:
2.3. jvisualvm
jvisualvm — это инструмент с графическим пользовательским интерфейсом, который позволяет нам отслеживать, устранять неполадки и профилировать приложения Java . Графический интерфейс простой, но очень интуитивно понятный и простой в использовании.
Одна из его многочисленных опций позволяет нам захватить дамп потока. Если мы щелкнем правой кнопкой мыши процесс Java и выберем опцию «Дамп
потока» , инструмент создаст дамп потока и откроет его на новой вкладке:
Начиная с JDK 9, Visual VM не входит в дистрибутивы Oracle JDK и Open JDK. Поэтому, если мы используем Java 9 или более новые версии, мы можем получить JVisualVM с сайта проекта Visual VM с открытым исходным кодом .
2.4. jcmd
jcmd — это инструмент, который работает, отправляя командные запросы в JVM. Несмотря на свою мощь, он не содержит удаленных функций; мы должны использовать его на той же машине, где запущен процесс Java.
Одна из его многочисленных команд — Thread.print
. Мы можем использовать его для получения дампа потока, просто указав pid
процесса:
jcmd 17264 Thread.print
2.5. jconsole
jconsole позволяет нам проверять трассировку стека каждого потока. Если мы откроем jconsole
и подключимся к запущенному процессу Java, мы сможем перейти на вкладку Threads
и найти трассировку стека каждого потока :
2.6. Резюме
Как оказалось, есть много способов получить дамп потока с помощью утилит JDK. Давайте поразмыслим над каждым из них и обозначим их плюсы и минусы:
jstack
: обеспечивает самый быстрый и простой способ захвата дампа потока; однако, начиная с Java 8, доступны лучшие альтернативы.jmc
: улучшенный инструмент профилирования и диагностики JDK. Это сводит к минимуму нагрузку на производительность, которая обычно возникает при использовании инструментов профилирования.jvisualvm
: легкий инструмент профилирования с открытым исходным кодом и отличной консолью с графическим интерфейсом.jcmd
: чрезвычайно мощный и рекомендуется для Java 8 и более поздних версий. Единый инструмент, который служит многим целям: захват дампа потока (jstack
), дампа кучи (jmap
), системных свойств и аргументов командной строки (jinfo
)jconsole
: позволяет нам проверять информацию о трассировке стека потока
3. Из командной строки
На корпоративных серверах приложений из соображений безопасности устанавливается только JRE. Таким образом, мы не можем использовать вышеупомянутые утилиты, так как они являются частью JDK. Однако существуют различные альтернативы командной строки, которые позволяют нам легко захватывать дампы потоков.
3.1. команда kill
-3 (Linux/Unix)
Самый простой способ захватить дамп потока в Unix-подобных системах — использовать команду kill
, которую мы можем использовать для отправки сигнала процессу с помощью системного вызова kill() .
В этом случае мы отправим ему сигнал -3 .
Используя тот же pid
из предыдущих примеров, давайте посмотрим, как использовать kill
для захвата дампа потока:
kill -3 17264
Таким образом, процесс Java, принимающий сигнал, выведет дамп потока на стандартный вывод.
Если мы запустим процесс Java со следующей комбинацией флагов настройки, то он также перенаправит дамп потока в данный файл:
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=~/jvm.log
Теперь, если мы отправим сигнал -3
, помимо стандартного вывода, дамп будет доступен в файле ~/jvm.log
.
3.2. Ctrl + Перерыв (Windows)
В операционных системах Windows мы можем захватить дамп потока с помощью комбинации клавиш CTRL
и Break
. Чтобы получить дамп потока, перейдите к консоли, используемой для запуска приложения Java, и одновременно нажмите клавиши CTRL
и Break
.
Стоит отметить, что на некоторых клавиатурах клавиша Break
недоступна. Поэтому в таких случаях дамп потока можно захватить с помощью клавиш CTRL
, SHIFT
и Pause
вместе.
Обе эти команды выводят дамп потока на консоль.
4. Программное использование ThreadMxBean
Последний подход, который мы обсудим в этой статье, — это использование JMX . Мы будем использовать ThreadMxBean
для захвата дампа потока . Давайте посмотрим на это в коде:
private static String threadDump(boolean lockedMonitors, boolean lockedSynchronizers) {
StringBuffer threadDump = new StringBuffer(System.lineSeparator());
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {
threadDump.append(threadInfo.toString());
}
return threadDump.toString();
}
В приведенной выше программе мы выполняем несколько шагов:
- Сначала инициализируется пустой
StringBuffer
для хранения информации о стеке каждого потока. - Затем мы используем класс
ManagementFactory
для получения экземпляраThreadMxBean.
ManagementFactory
— это фабричный класс для получения управляемых компонентов для платформы Java. Кроме того,ThreadMxBean
— это интерфейс управления системой потоков JVM. - Если задать для
LockMonitors
иLockSynchronizers
значениеtrue
, это означает, что синхронизаторы, которыми можно владеть, и все заблокированные мониторы будут захвачены в дамп потока.
5. Вывод
В этой статье мы узнали о нескольких способах захвата дампа потока.
Сначала мы обсудили различные утилиты JDK, а затем альтернативы командной строки. Наконец, мы остановились на программном подходе с использованием JMX.
Как всегда, полный исходный код примера доступен на GitHub .