how to analyze thread dumps

Abstract

A thread dump contains all active thread at one time. It contains all the information on the threads and their current states, presented in stacks. Thread dumps can be used to:

  • optimize JVM performance
  • optimize application performance
  • investigate issues, like conflicts

There are multiple ways to create a thread dump:

  • using jstack -l <pid>
  • using jvisualvm
  • using jcmd <pid> Thread.print
  • using jmc
  • using jconsole
  • using ThreadMxBean

Reviews

2024-07-13

Those are mandatory tools used for analyzing java applications. I honestly only used those once in my lifetime, when some applications crashed or were too slow.

Nous discuterons également de la manière dont cela aide à identifier les problèmes et certains des analyseurs que vous pouvez utiliser.

What is Thread?

Un processus est un programme informatique chargé dans la mémoire de l’ordinateur et en cours d’exécution. Il peut être exécuté par un processeur ou un ensemble de processeurs. Un processus est décrit en mémoire avec des informations importantes telles que les magasins de variables, les descripteurs de fichiers, le compteur de programme, les registres et les signaux, etc.

Un processus peut être constitué de nombreux processus légers appelés discussions. Cela permet d’obtenir un parallélisme dans lequel un processus est divisé en plusieurs threads. Cela se traduit par de meilleures performances. Tous les threads d’un processus partagent le même espace mémoire et dépendent les uns des autres.

Dumps de thread

Lorsque le processus est en cours d’exécution, nous pouvons détecter l’état d’exécution actuel du threads dans le processus à l’aide de thread dumps. Un thread Dump contient un instantané de tous les threads actifs à un moment donné pendant l’exécution d’un programme. Il contient toutes les informations pertinentes sur le thread et son état actuel.

Une application moderne implique aujourd’hui plusieurs nombres de threads. Chaque thread nécessite certaines ressources, effectue certaines activités liées au processus. Cela peut améliorer les performances d’une application car les threads peuvent utiliser les cœurs de processeur disponibles.

Mais il y a des compromis, par exemple, parfois plusieurs threads peuvent ne pas bien se coordonner et une situation de blocage peut survenir. Donc, si quelque chose ne va pas, nous pouvons utiliser des vidages de threads pour inspecter l’état de nos threads.

Thread dump in Java

Un vidage de thread JVM est une liste de l’état de tous les threads qui font partie du processus à ce moment précis. Il contient des informations sur la pile du thread, présentées sous forme de trace de pile. Comme il est écrit en texte brut, le contenu peut être enregistré pour une révision ultérieure. L’analyse des thread dumps peut aider

  • Optimiser les performances de la JVM
  • Optimisation des performances de l’application
  • Diagnostiquer des problèmes, par exemple un blocage, un conflit de threads, etc.

Generation of Thread Dumps

Il existe de nombreuses façons de générer des threads de vidage. Vous trouverez ci-dessous quelques outils basés sur JVM et peuvent être exécutés à partir de la ligne de commande / du terminal (outils CLI) ou du / bin (GUI tools) répertoire du dossier d’installation de Java.

Explorons-les.

# 1. jStackName

Le moyen le plus simple de générer un vidage de thread est d’utiliser jStack. jStack est livré avec JVM et peut être utilisé à partir de la ligne de commande. Ici, nous avons besoin du PID du processus pour lequel nous voulons générer le thread dump. Pour obtenir le PID, nous pouvons utiliser JPS comme indiqué ci-dessous.

jps -l

jps répertorie tous les identifiants de processus Java.

Sur Windows

C:\Program Files\Java\jdk1.8.0_171\bin>jps -l
47172 portal
6120 sun.tools.jps.Jps
C:\Program Files\Java\jdk1.8.0_171\bin>

Sous Linux

[geekfkare@localhost ~]# jps -l
1088 /opt/keycloak/jboss-modules.jar
26680 /var/lib/jenkins/workspace/kyc/kyc/target/kyc-1.0.jar
7193 jdk.jcmd/sun.tools.jps.Jps
2058 /usr/share/jenkins/jenkins.war
11933 /var/lib/jenkins/workspace/admin-portal/target/portal-1.0.jar
[geekfkare@localhost ~]#

Comme nous pouvons le voir ici, nous obtenons une liste de tous les processus java en cours d’exécution. Il contient l’ID de machine virtuelle locale pour le processus java en cours d’exécution et le nom de l’application dans les colonnes un et deux respectivement. Maintenant, pour générer le thread dump, nous utilisons le jStackName programme avec Il indicateur qui crée une sortie longue liste du vidage. Nous pouvons également diriger la sortie vers un fichier texte de notre choix.

jstack -l 26680

[geekfkare@localhost ~]# jstack -l 26680
2020-06-27 06:04:53
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
 
"Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
   Locked ownable synchronizers:
        - None
 
"logback-8" #2316 daemon prio=5 os_prio=0 tid=0x00007f07e0033000 nid=0x4792 waiting on condition [0x00007f07baff8000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
 
   Locked ownable synchronizers:
        - None
 
"logback-7" #2315 daemon prio=5 os_prio=0 tid=0x00007f07e0251800 nid=0x4791 waiting on condition [0x00007f07bb0f9000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
 
   Locked ownable synchronizers:
        - None

# 2. jvisualvm

Jvisualvm est un outil graphique qui nous aide à dépanner, surveiller et profiler les applications Java. Il est également livré avec JVM et peut être lancé à partir du / bin répertoire de notre installation java. Il est très intuitif et facile à utiliser. Entre autres options, il nous permet également de capturer le vidage de thread pour un processus particulier.

Pour afficher le thread dump pour un processus particulier, nous pouvons faire un clic droit sur le programme et sélectionner Décharge de thread dans le menu contextuel.

svg%3E

# 3. jcmd

JCMD est un utilitaire de ligne de commande livré avec le JDK et utilisé pour envoyer des requêtes de commande de diagnostic à la JVM.

Il ne fonctionne cependant que sur la machine locale sur laquelle l’application Java est en cours d’exécution. Il peut être utilisé pour contrôler les enregistrements de vol Java, diagnostiquer et dépanner les applications JVM et Java. Nous pouvons utiliser le Thread.print commande de jcmd pour obtenir une liste des vidages de threads pour un processus particulier spécifié par le PID.

Voici un exemple de la façon dont nous pouvons utiliser jcmd.

jcmd 28036 Thread.print

C:\Program Files\Java\jdk1.8.0_171\bin>jcmd 28036 Thread.print
28036:
2020-06-27 21:20:02
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode):
 
"Bundle File Closer" #14 daemon prio=5 os_prio=0 tid=0x0000000021d1c000 nid=0x1d4c in Object.wait() [0x00000000244ef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Unknown Source)
        at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.getNextEvent(EventManager.java:403)
        - locked <0x000000076f380a88> (a org.eclipse.osgi.framework.eventmgr.EventManager$EventThread)
        at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:339)
 
"Active Thread: Equinox Container: 0b6cc851-96cd-46de-a92b-253c7f7671b9" #12 prio=5 os_prio=0 tid=0x0000000022e61800 nid=0xbff4 waiting on condition [0x00000000243ee000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x000000076f388188> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
 
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000021a7b000 nid=0x2184 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x00000000219f5000 nid=0x1300 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000219e0000 nid=0x48f4 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000219df000 nid=0xb314 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000219db800 nid=0x2260 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000219d9000 nid=0x125c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000219d8000 nid=0x834 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001faf3000 nid=0x36c0 in Object.wait() [0x0000000021eae000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        - locked <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
 
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000005806000 nid=0x13c0 in Object.wait() [0x00000000219af000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076f398178> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Unknown Source)
        at java.lang.ref.Reference.tryHandlePending(Unknown Source)
        - locked <0x000000076f398178> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
 
"main" #1 prio=5 os_prio=0 tid=0x000000000570e800 nid=0xbf8 runnable [0x0000000000fec000]
   java.lang.Thread.State: RUNNABLE
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.<init>(Unknown Source)
        at java.util.zip.ZipFile.<init>(Unknown Source)
        at java.util.zip.ZipFile.<init>(Unknown Source)
        at org.eclipse.osgi.framework.util.SecureAction.getZipFile(SecureAction.java:307)
        at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getZipFile(ZipBundleFile.java:136)
        at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.lockOpen(ZipBundleFile.java:83)
        at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getEntry(ZipBundleFile.java:290)
        at org.eclipse.equinox.weaving.hooks.WeavingBundleFile.getEntry(WeavingBundleFile.java:65)
        at org.eclipse.osgi.storage.bundlefile.BundleFileWrapper.getEntry(BundleFileWrapper.java:55)
        at org.eclipse.osgi.storage.BundleInfo$Generation.getRawHeaders(BundleInfo.java:130)
        - locked <0x000000076f85e348> (a java.lang.Object)
        at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:599)
        at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:1)
        at org.eclipse.equinox.weaving.hooks.SupplementerRegistry.addSupplementer(SupplementerRegistry.java:172)
        at org.eclipse.equinox.weaving.hooks.WeavingHook.initialize(WeavingHook.java:138)
        at org.eclipse.equinox.weaving.hooks.WeavingHook.start(WeavingHook.java:208)
        at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startActivator(FrameworkExtensionInstaller.java:261)
        at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startExtensionActivators(FrameworkExtensionInstaller.java:198)
        at org.eclipse.osgi.internal.framework.SystemBundleActivator.start(SystemBundleActivator.java:112)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:815)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:808)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:765)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1005)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule.initWorker(EquinoxBundle.java:190)
        at org.eclipse.osgi.container.SystemModule.init(SystemModule.java:99)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:272)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:257)
        at org.eclipse.osgi.launch.Equinox.init(Equinox.java:171)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:316)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:251)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:661)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:597)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1476)
 
"VM Thread" os_prio=2 tid=0x000000001fae8800 nid=0x32cc runnable
 
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000005727800 nid=0x3264 runnable
 
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000005729000 nid=0xbdf4 runnable
 
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000572a800 nid=0xae6c runnable
 
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000572d000 nid=0x588 runnable
 
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000572f000 nid=0xac0 runnable
 
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000005730800 nid=0x380 runnable
 
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000005733800 nid=0x216c runnable
 
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000005734800 nid=0xb930 runnable
 
"VM Periodic Task Thread" os_prio=2 tid=0x0000000021a8d000 nid=0x2dcc waiting on condition
 
JNI global references: 14
 
 
C:\Program Files\Java\jdk1.8.0_171\bin>

# 4. JMC

JMC signifie Contrôle de mission Java. Il s’agit d’un outil d’interface graphique open source fourni avec JDK et utilisé pour collecter et analyser les données d’application Java.

Il peut être lancé depuis le / bin dossier de notre installation Java. Les administrateurs et développeurs Java utilisent l’outil pour recueillir des informations détaillées de bas niveau sur les comportements de la JVM et de l’application. Il permet une analyse détaillée et efficace des données collectées par Java Enregistreur de vol.

Au lancement jmc, nous pouvons voir la liste des processus java qui s’exécutent sur la machine locale. Une connexion à distance est également possible. Sur un processus particulier, nous pouvons faire un clic droit et choisir Démarrer l’enregistrement de vol puis vérifiez les décharges de thread dans le Threads languette.

svg%3E

# 5. jconsole

jconsole est un outil d’extension de gestion Java utilisé pour la gestion et la surveillance des plaintes.

Il dispose également d’un ensemble d’opérations prédéfinies sur l’agent JMX que l’utilisateur peut effectuer. Il permet à l’utilisateur de détecter et d’analyser la trace de pile d’un programme en direct. Il peut être lancé depuis le / bin dossier de notre installation Java.

En utilisant l’ jconsole Outil GUI, nous pouvons inspecter la trace de la pile de chaque thread lorsque nous le connectons à un processus Java en cours d’exécution. Ensuite, dans l’onglet Thread, nous pouvons voir le nom de tous les threads en cours d’exécution. Pour détecter une impasse, nous pouvons cliquer sur le Détecter le blocage en bas à droite de la fenêtre. Si un blocage est détecté, il apparaîtra dans un nouvel onglet sinon un Aucun blocage détecté Sera affiché.

svg%3E

# 6. ThreadMxBean

ThreadMXBean est l’interface de gestion du système de threads de la machine virtuelle Java appartenant au package java.lang.Management. Il est principalement utilisé pour détecter les threads qui sont entrés dans une situation de blocage et obtenir des détails à leur sujet.

Nous pouvons utiliser l’interface ThreadMxBean pour capturer par programme le vidage de thread. getThreadMXBean() méthode de ManagementFactory est utilisé pour obtenir une instance de ThreadMXBean interface. Il renvoie le nombre de threads en direct démon et non démon. ManagementFactory est une classe d’usine permettant d’obtenir les beans gérés pour la plate-forme Java.

private static String getThreadDump (boolean lockMonitors, boolean lockSynchronizers) {
    StringBuffer threadDump = new StringBuffer (System.lineSeparator ());
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean ();
    for (ThreadInfo threadInfo : threadMXBean.dumpAllThreads (lockMonitors, lockSynchronizers)) {
        threadDump.append (threadInfo.toString ());
    }
    return threadDump.toString ();
}

Manual Analysis of Thread Dumps

L’analyse des vidages de threads peut être très utile pour identifier les problèmes dans les processus multithreads. Les problèmes tels que les blocages, les conflits de verrouillage et l’utilisation excessive du processeur par les vidages de thread individuels peuvent être résolus en visualisant les états des vidages de thread individuels.

Le débit maximal de l’application peut être atteint en rectifiant l’état de chaque thread après avoir analysé le vidage de thread.

Par exemple, disons, un processus utilise beaucoup de CPU, nous pouvons savoir si un thread utilise le plus le CPU. S’il existe un tel thread, nous convertissons son numéro LWP en un nombre hexadécimal. Ensuite, à partir du vidage de thread, nous pouvons trouver le thread avec nid égal au nombre hexadécimal obtenu précédemment. En utilisant la trace de pile du thread, nous pouvons identifier le problème. Découvrons l’identifiant de processus du thread à l’aide de la commande ci-dessous.

ps -mo pid,lwp,stime,time,cpu -C java

[geekfkare@localhost ~]# ps -mo pid,lwp,stime,time,cpu -C java
       PID        LWP         STIME           TIME              %CPU
26680               -        Dec07          00:02:02           99.5
         -      10039        Dec07          00:00:00           0.1
         -      10040        Dec07          00:00:00           95.5

Jetons un coup d’œil au morceau ci-dessous du vidage de thread. Pour obtenir un vidage de thread pour le processus 26680, utilisez jstack -l 26680

[geekfkare@localhost ~]# jstack -l 26680
2020-06-27 09:01:29
<strong>Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):</strong>
 
"Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
 
   Locked ownable synchronizers:
        - None
 
.
.
.
.
.
.
.
"<strong>Reference Handler</strong>" #2 daemon prio=10 os_prio=0 tid=0x00007f085814a000 nid=0x6840 in Object.wait() [0x00007f083b2f1000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x00000006c790fbd0> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
 
   Locked ownable synchronizers:
        - None
 
"VM Thread" os_prio=0 tid=0x00007f0858140800 nid=0x683f runnable
 
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f0858021000 nid=0x683b runnable
 
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f0858022800 nid=0x683c runnable
 
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f0858024800 nid=0x683d runnable
 
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f0858026000 nid=0x683e runnable
 
"VM Periodic Task Thread" os_prio=0 tid=0x00007f08581a0000 nid=0x6847 waiting on condition
 
JNI global references: 1553

Voyons maintenant quelles sont les choses que nous pouvons explorer à l’aide de threads dumps. Si nous observons le vidage des threads, nous pouvons voir beaucoup de contenu, ce qui peut être écrasant. Cependant, si nous faisons un pas à la fois, cela peut être assez simple à comprendre. Comprenons la première ligne

2020-06-27 09:01:29
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):

Ce qui précède affiche l’heure à laquelle le vidage a été généré et des informations sur la machine virtuelle Java utilisée. Ensuite, à la fin, nous pouvons voir la liste des fils, le premier d’entre eux est notre Gestionnaire de référence fil.

Analyse des threads bloqués

Si nous analysons les journaux de vidage de thread ci-dessous, nous pouvons constater qu’il a détecté des threads avec BLOQUÉ statut qui rend les performances d’une application très lentes. Donc, si nous pouvons trouver le BLOQUÉ threads, nous pouvons essayer d’extraire les threads liés aux verrous que les threads tentent d’obtenir. L’analyse de la trace de la pile du thread qui détient actuellement le verrou peut aider à résoudre le problème.

[geekfkare@localhost ~]# jstack -l 26680
.
.
.
.
" DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
"DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
.
.
.
.

Analyse d’un thread bloqué

Une autre application très courante des thread dumps est la détection de impasses. La détection et la résolution des blocages peuvent être beaucoup plus faciles si nous analysons les décharges de threads.

Un blocage est une situation impliquant au moins deux threads où la ressource requise par un thread pour continuer l’exécution est verrouillée par un autre thread et en même temps, la ressource requise par le second thread est verrouillée par le premier thread.

Ainsi, aucun des threads ne peut continuer l’exécution, ce qui entraîne une situation de blocage et le blocage de l’application. Si des dreadlocks sont présents, la dernière section du thread dump imprimera les informations concernant le blocage comme suit.

"Thread-0":
waiting to lock monitor 0x00000250e4982480 (object 0x00000000894465b0, a java.lang.Object),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x00000250e4982380 (object 0x00000000894465a0, a java.lang.Object),
which is held by "Thread-0"
.
.
.
"Thread-0":
at DeadlockedProgram$DeadlockedRunnableImplementation.run(DeadlockedProgram.java:34)
- waiting to lock <0x00000000894465b0> (a java.lang.Object)
- locked <0x00000000894465a0> (a java.lang.Object)
at java.lang.Thread.run(java.base@10.0.1/Thread.java:844)
"Thread-1":
at DeadlockedProgram $DeadlockRunnableImplementation.run(DeadlockedProgram.java:34)
- waiting to lock <0x00000000894465a0> (a java.lang.Object)
- locked <0x00000000894465b0> (a java.lang.Object)
at java.lang.Thread.run(java.base@10.0.1/Thread.java:844)

Ici, nous pouvons voir les informations de blocage dans un format assez lisible par l’homme.

En dehors de cela, si nous résumons tous les morceaux ci-dessus de vidage de threads ensemble, il indique les informations ci-dessous.

  • Gestionnaire de rĂ©fĂ©rence est le nom lisible par l’homme du thread.
  • #2 est l’identifiant unique du thread.
  • dĂ©mon indique si le thread est un thread dĂ©mon.
  • La prioritĂ© numĂ©rique du thread est donnĂ©e par prio= 10.
  • L’état actuel du thread est indiquĂ© par attente sous condition.
  • Ensuite, nous voyons la trace de la pile, qui comprend les informations de verrouillage.

Thread Dumps Analyzers

Outre l’analyse manuelle, il existe de nombreux outils disponibles pour analyser les threads, à la fois en ligne et hors ligne. Vous trouverez ci-dessous certains des outils répertoriés, que nous pouvons utiliser en fonction des besoins.

Tout d’abord, explorons les outils en ligne.

# 1. Fil rapide

Filetage rapide est DevOps l’outil d’analyse de vidage de thread préféré de l’ingénieur pour résoudre les problèmes de production complexes. Il s’agit d’un analyseur de vidage de thread Java en ligne.Nous pouvons télécharger le vidage de thread en tant que fichier ou nous pouvons directement copier et coller le vidage de thread.

En fonction de la taille, il analysera le vidage de thread et affichera les informations comme indiqué dans la capture d’écran.

svg%3E

En vedette

  • DĂ©panner les plantages JVM, les ralentissements, les fuites de mĂ©moire, les blocages, les pics de processeur
  • RCA instantanĂ© (n’attendez pas les fournisseurs)
  • Tableau de bord intuitif
  • Prise en charge de l’API REST
  • Machine Learning

# 2. Analyseur de vidage de thread Spotify

Le Analyseur de vidage de thread Spotify est sous licence sous la version 2.0 de la licence Apache. C’est un outil en ligne et accepte le thread dump sous forme de fichier ou nous pouvons directement copier et coller le thread dump. En fonction de la taille, il analysera le vidage du thread et affichera les informations comme indiqué dans la capture d’écran.

svg%3E

# 3. Revue de Jstack

Jstack.revue analyse les vidages de threads Java depuis le navigateur. Cette page est uniquement côté client.

svg%3E

# 4. Site Web 24 Ă— 7

Cette outil est une condition préalable à la détection des threads défectueux dégradant les performances de la machine virtuelle Java (JVM). Les problèmes tels que les blocages, les conflits de verrouillage et l’utilisation excessive du processeur par les vidages de thread individuels peuvent être résolus en visualisant les états des vidages de thread individuels.

Le débit maximal de l’application peut être atteint en rectifiant l’état de chaque thread fourni par l’outil.

svg%3E

Maintenant, explorons les outils hors ligne.

En matière de profilage, seul le meilleur outil est assez bon.

# 1. JProfilerName

JProfilerName est l’un des analyseurs de vidage de thread les plus populaires parmi Développeurs Java. L’interface utilisateur intuitive de JProfiler vous aide à résoudre les goulots d’étranglement des performances, à identifier les fuites de mémoire et à comprendre les problèmes de thread.

JProfilerName

JProfiler prend en charge le profilage sur les plates-formes suivantes:

  • Windows
  • MacOS
  • Linux
  • FreeBSD
  • Solaris
  • AIX
  • HP-UX

Voici quelques fonctionnalités qui font de JProfiler le premier choix pour le profilage de nos applications sur la JVM.

En vedette

  • Prend en charge le profilage de base de donnĂ©es pour JDBC, JPA et NoSQL
  • La prise en charge de l’édition d’entreprise Java est Ă©galement disponible
  • PrĂ©sente des informations de haut niveau sur les appels RMI
  • Analyse stellaire des fuites de mĂ©moire
  • CapacitĂ©s d’assurance qualitĂ© Ă©tendues
  • Le profileur de thread intĂ©grĂ© est Ă©troitement intĂ©grĂ© aux vues de profilage du processeur.
  • Prise en charge des plates-formes, des IDE et des serveurs d’applications.

# 2. IBM TMDA

IBM Thread and Monitor Dump Analyzer pour Java (TMDA) est un outil qui permet d’identifier les blocages, les blocages, les conflits de ressources et les goulots d’étranglement dans les vidages de thread Java. Il s’agit d’un produit IBM mais l’outil TMDA est fourni sans aucune garantie ni assistance; cependant, ils essaient de réparer et d’améliorer l’outil au fil du temps.

svg%3E

# 3. ManageEngine

ManageEngine Le gestionnaire d’applications peut aider à surveiller la mémoire JVM Heap et Non-Heap. Nous pouvons même configurer des seuils et être alerté par e-mail, SMS, etc., et nous assurer qu’une application Java est bien réglée.

svg%3E

# 4. VotreTrousse

VotreTrousse se compose des produits ci-dessous appelés sous forme de kit.

  • Java Profiler - Profileur Ă  faible coĂ»t complet complet pour les plates-formes Java EE et Java SE.
  • YouMonitor – Surveillance des performances et profilage des Jenkins, Team City, Gradle, Maven, Ant, JUnit et TestNG.
  • .NET Profiler - Profileur de performances et de mĂ©moire facile Ă  utiliser pour le framework .NET.

Conclusion

Vous savez maintenant à quel point les vidages de threads sont utiles pour comprendre et diagnostiquer les problèmes dans les applications multithread. Avec bon le savoir, concernant les thread dumps - leur structure, les informations qu’ils contiennent, etc. - nous pouvons les utiliser pour identifier rapidement les causes des problèmes.