Заснемане на Java Thread Dump

1. Общ преглед

В този урок ще обсъдим различни начини за улавяне на дъмп на нишка на Java приложение.

Дъмпингът на нишки е моментна снимка на състоянието на всички нишки на Java процес . Състоянието на всяка нишка е представено с проследяване на стека, показващо съдържанието на стека на нишка. Дъмпингът на нишка е полезен за диагностициране на проблеми, тъй като показва активността на нишката. Изхвърлянията на нишки са написани в обикновен текст, така че можем да запазим съдържанието им във файл и да ги разгледаме по-късно в текстов редактор .

В следващите раздели ще преминем през множество инструменти и подходи за генериране на дъмп на нишка.

2. Използване на JDK Utilities

JDK предоставя няколко помощни програми, които могат да заснемат дъмп на нишка на Java приложение. Всички помощни програми се намират под папката bin в домашната директория на JDK . Следователно можем да изпълним тези помощни програми от командния ред, стига тази директория да е в нашия системен път.

2.1. jstack

jstack е помощната програма на JDK от командния ред, която можем да използваме за улавяне на дамп на нишка. Взима pid на процес и показва дъмп на конци в конзолата. Като алтернатива можем да пренасочим изхода му към файл.

Нека да разгледаме основния синтаксис на командата за улавяне на дамп на нишка с помощта на jstack:

jstack [-F] [-l] [-m] 

Всички знамена не са задължителни. Нека видим какво означават те:

  • -F опция принуждава изхвърляне на нишка; удобен за използване, когато jstack pid не реагира (процесът е закачен)
  • -l опцията инструктира помощната програма да търси собствени синхронизатори в купчината и ключалките
  • -m опция отпечатва естествени рамки на стека (C & C ++) в допълнение към рамките на Java стека

Нека използваме тези знания, като заснемем дамп на нишка и пренасочим резултата към файл:

jstack 17264 > /tmp/threaddump.txt

Не забравяйте, че можем лесно да получим pid на Java процес с помощта на jps командата.

2.2. Контрол на мисията на Java

Java Mission Control (JMC) е GUI инструмент, който събира и анализира данни от Java приложения. След като стартираме JMC, той показва списъка на Java процеси, работещи на локална машина. Също така можем да се свържем с отдалечени Java процеси чрез JMC.

Можем да щракнем с десния бутон върху процеса и да кликнете върху опцията „ Стартиране на запис на полет “. След това в раздела Threads се извеждат нишките на нишките :

2.3. jvisualvm

jvisualvm е инструмент с графичен потребителски интерфейс, който ни позволява да наблюдаваме, отстраняваме и профилираме Java приложения . GUI е прост, но много интуитивен и лесен за използване.

Една от многото му опции ни позволява да заснемем изхвърляне на нишка. Ако щракнем с десния бутон на мишката върху процес на Java и изберем опцията “Thread Dump” , инструментът ще създаде дъмп на нишка и ще го отвори в нов раздел:

От 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 : лек и инструмент за профилиране с отворен код с отлична GUI конзола
  • jcmd : изключително мощен и се препоръчва за Java 8 и по-нови версии. Един инструмент, който служи за много цели - улавяне на изхвърляне на нишка ( jstack ), изхвърляне на купчина ( jmap ), системни свойства и аргументи от командния ред ( jinfo )
  • jconsole : нека проверим информацията за проследяване на стека на нишки

3. От командния ред

В сървърите за корпоративни приложения само JRE е инсталиран от съображения за сигурност. По този начин не можем да използваме гореспоменатите помощни програми, тъй като те са част от JDK. Съществуват обаче различни алтернативи на командния ред, които ни позволяват лесно да улавяме сметища на нишки.

3.1. kill -3 Command (Linux / Unix)

Най-лесният начин за улавяне на дамп на нишка в Unix-подобни системи е чрез командата kill , която можем да използваме, за да изпратим сигнал към процес, използвайки системното повикване kill () . В този случай ще му изпратим сигнала -3 .

Използвайки нашия същият pid от по-ранни примери, нека да разгледаме как да използваме kill за улавяне на изхвърляне на нишка:

kill -3 17264

This way the signal-receiving Java process will print the thread dump on the standard output.

If we run the Java process with the following combination of tuning flags, then it will also redirect the thread dump to the given file:

-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=~/jvm.log

Now if we send the -3 signal, in addition to the standard output, the dump will be available at ~/jvm.log file.

3.2. Ctrl + Break (Windows)

In Windows operating systems, we can capture a thread dump using the CTRL and Break key combination. To take a thread dump, navigate to the console used to launch the Java application and press CTRL and Break keys together.

It's worth noting that, on some keyboards, the Break key is not available. Therefore, in such cases, a thread dump can be captured using CTRL, SHIFT, and Pause keys together.

Both of these commands print the thread dump to the console.

4. Programmatically Using ThreadMxBean

The last approach we will discuss in the article is using JMX. We'll use ThreadMxBean to capture the thread dump. Let's see it in code:

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

In the above program, we are performing several steps:

  1. At first, an empty StringBuffer is initialized to hold the stack information of each thread.
  2. We then use the ManagementFactory class to get the instance of ThreadMxBean. A ManagementFactory is a factory class for getting managed beans for the Java platform. In addition, a ThreadMxBean is the management interface for the thread system of the JVM.
  3. Setting lockedMonitors and lockedSynchronizers values to true indicates to capture the ownable synchronizers and all locked monitors in the thread dump.

5. Conclusion

In this article, we've shown multiple ways to capture a thread dump.

At first, we discussed various JDK Utilities and then the command-line alternatives. In the last section, we concluded with the programmatic approach using JMX.

Както винаги, пълният изходен код на примера е достъпен в GitHub.