Перейти к основному содержимому

Получение дампа потока Java

· 6 мин. чтения

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 отображаются дампы потоков:

./24f653707bcd29a63c52a0b6f92a3b97.png

2.3. jvisualvm

jvisualvm — это инструмент с графическим пользовательским интерфейсом, который позволяет нам отслеживать, устранять неполадки и профилировать приложения Java . Графический интерфейс простой, но очень интуитивно понятный и простой в использовании.

Одна из его многочисленных опций позволяет нам захватить дамп потока. Если мы щелкнем правой кнопкой мыши процесс Java и выберем опцию «Дамп потока» , инструмент создаст дамп потока и откроет его на новой вкладке:

./d651b7ba26ced41d010ad2bca8fd8e8e.png

Начиная с 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 и найти трассировку стека каждого потока :

./77751257b37b8ed1dcf3de1aace1ec7f.png

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

В приведенной выше программе мы выполняем несколько шагов:

  1. Сначала инициализируется пустой StringBuffer для хранения информации о стеке каждого потока.
  2. Затем мы используем класс ManagementFactory для получения экземпляра ThreadMxBean. ManagementFactory — это фабричный класс для получения управляемых компонентов для платформы Java. Кроме того, ThreadMxBean — это интерфейс управления системой потоков JVM.
  3. Если задать для LockMonitors и LockSynchronizers значение true , это означает, что синхронизаторы, которыми можно владеть, и все заблокированные мониторы будут захвачены в дамп потока.

5. Вывод

В этой статье мы узнали о нескольких способах захвата дампа потока.

Сначала мы обсудили различные утилиты JDK, а затем альтернативы командной строки. Наконец, мы остановились на программном подходе с использованием JMX.

Как всегда, полный исходный код примера доступен на GitHub .