Wat is Thread Dump en hoe deze te analyseren?

Laten we het hebben over de threaddump en hoe deze te analyseren.

We zullen ook bespreken hoe het helpt om de problemen te lokaliseren en een deel van de analysator die u kunt gebruiken.

Wat is Draad?

Een proces is een computerprogramma dat in het geheugen van de computer wordt geladen en wordt uitgevoerd. Het kan worden uitgevoerd door een processor of een set processors. Een proces wordt in het geheugen beschreven met belangrijke informatie zoals variabelenopslag, bestandshandvatten, de programmateller, registers en signalen, enzovoort.

Een proces kan bestaan ​​uit vele lichtgewicht processen die threads worden genoemd. Dit helpt om parallellisme te bereiken waarbij een proces is verdeeld in meerdere threads. Dit resulteert in betere prestaties. Alle threads binnen een proces delen dezelfde geheugenruimte en zijn van elkaar afhankelijk.

Draad dumpt

Wanneer het proces wordt uitgevoerd, kunnen we de huidige uitvoeringsstatus van de threads in het proces detecteren met behulp van threaddumps. Een threaddump bevat een momentopname van alle threads die actief zijn op een bepaald punt tijdens de uitvoering van een programma. Het bevat alle relevante informatie over de thread en de huidige status.

Een moderne applicatie omvat tegenwoordig meerdere aantallen threads. Elke thread vereist bepaalde bronnen, voert bepaalde activiteiten uit die verband houden met het proces. Dit kan de prestaties van een toepassing verbeteren, aangezien threads beschikbare CPU-kernen kunnen gebruiken.

Maar er zijn afwegingen, bijvoorbeeld, soms kunnen meerdere threads niet goed met elkaar worden gecoördineerd en kan er een impasse ontstaan. Dus als er iets misgaat, kunnen we thread-dumps gebruiken om de staat van onze threads te inspecteren.

Draaddump in Java

Een JVM-threaddump is een lijst met de status van alle threads die op dat specifieke moment deel uitmaken van het proces. Het bevat informatie over de stack van de thread, gepresenteerd als een stacktracering. Omdat het in platte tekst is geschreven, kan de inhoud worden opgeslagen om later te bekijken. Analyse van threaddumps kan daarbij helpen

  • JVM-prestaties optimaliseren
  • Applicatieprestaties optimaliseren
  • Diagnose stellen van problemen, bijv. een impasse, discussie over threads, enz.

Genereren van threaddumps

Er zijn veel manieren om threaddumps te genereren. Hieronder staan ​​enkele op JVM gebaseerde tools die kunnen worden uitgevoerd vanaf de opdrachtregel/terminal (CLI-tools) of de map /bin (GUI-tools) van de installatiemap van Java.

Laten we ze verkennen.

#1. jStapel

De eenvoudigste manier om een ​​threaddump te genereren is door jStack te gebruiken. jStack wordt geleverd met JVM en kan vanaf de opdrachtregel worden gebruikt. Hier hebben we de PID nodig van het proces waarvoor we de threaddump willen genereren. Om PID te krijgen, kunnen we de opdracht jps gebruiken, zoals hieronder wordt weergegeven.

jps -l

jps somt alle Java-proces-ID’s op.

Op Windows

C:Program FilesJavajdk1.8.0_171bin>jps -l
47172 portal
6120 sun.tools.jps.Jps
C:Program FilesJavajdk1.8.0_171bin>

Op Linux

[[email protected] ~]# 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
[[email protected] ~]#

Zoals we hier kunnen zien, krijgen we een lijst met alle lopende Java-processen. Het bevat de lokale VM-id voor het lopende Java-proces en de naam van de toepassing in respectievelijk kolom één en twee. Om de threaddump te genereren, gebruiken we nu het jStack-programma met de vlag –l, waarmee een longlist-uitvoer van de dump wordt gemaakt. We kunnen de uitvoer ook doorsluizen naar een tekstbestand naar keuze.

jstack -l 26680

[[email protected] ~]# 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 is een GUI-tool die ons helpt bij het oplossen van problemen, het bewaken en het profileren van Java-applicaties. Het wordt ook geleverd met JVM en kan worden gestart vanuit de map /bin van onze java-installatie. Het is zeer intuïtief en gemakkelijk te gebruiken. Het stelt ons onder andere ook in staat om threaddump voor een bepaald proces vast te leggen.

Om de threaddump voor een bepaald proces te bekijken, kunnen we met de rechtermuisknop op het programma klikken en Threaddump selecteren in het contextmenu.

  Muziek toevoegen aan uw PowerPoint-presentatie

#3. jcmd

JCMD is een opdrachtregelhulpprogramma dat bij de JDK wordt geleverd en wordt gebruikt om diagnostische opdrachtverzoeken naar de JVM te sturen.

Het werkt echter alleen op de lokale computer waarop de Java-toepassing wordt uitgevoerd. Het kan worden gebruikt om Java Flight Recordings te besturen, JVM- en Java-applicaties te diagnosticeren en problemen op te lossen. We kunnen de opdracht Thread.print van jcmd gebruiken om een ​​lijst met threaddumps op te halen voor een bepaald proces gespecificeerd door de PID.

Hieronder is een voorbeeld van hoe we jcmd kunnen gebruiken.

jcmd 28036 Draad.afdruk

C:Program FilesJavajdk1.8.0_171bin>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 FilesJavajdk1.8.0_171bin>

#4. JMC

JMC staat voor Java Mission Control. Het is een open-source GUI-tool die wordt geleverd met JDK en wordt gebruikt om Java-toepassingsgegevens te verzamelen en te analyseren.

Het kan worden gestart vanuit de map /bin van onze Java-installatie. Java-beheerders en -ontwikkelaars gebruiken de tool om gedetailleerde informatie op laag niveau te verzamelen over het gedrag van de JVM en de toepassing. Het maakt een gedetailleerde en efficiënte analyse mogelijk van gegevens die zijn verzameld door Java Flight Recorder.

Bij het starten van jmc kunnen we een lijst met Java-processen zien die op de lokale computer worden uitgevoerd. Een verbinding op afstand is ook mogelijk. Bij een bepaald proces kunnen we met de rechtermuisknop klikken en Start Flight Recording kiezen en vervolgens de thread-dumps op het tabblad Threads controleren.

#5. jconsole

jconsole is een Java Management Extension-tool die wordt gebruikt voor klachtenbeheer en monitoring.

Het heeft ook een reeks vooraf gedefinieerde bewerkingen op de JMX-agent die de gebruiker kan uitvoeren. Het stelt de gebruiker in staat om stacktracering van een live programma te detecteren en te analyseren. Het kan worden gestart vanuit de map /bin van onze Java-installatie.

Met behulp van de jconsole GUI-tool kunnen we de stacktracering van elke thread inspecteren wanneer we deze verbinden met een lopend Java-proces. Vervolgens kunnen we op het tabblad Thread de naam van alle lopende threads zien. Om een ​​deadlock te detecteren, kunnen we klikken op Detecteer deadlock rechtsonder in het venster. Als er een impasse wordt gedetecteerd, verschijnt deze op een nieuw tabblad, anders wordt Geen deadlock gedetecteerd weergegeven.

  Fix Hulu-foutcode 406

#6. DraadMxBean

ThreadMXBean is de interface voor het beheer van het threadsysteem van de virtuele Java-machine die deel uitmaakt van het java.lang.Management-pakket. Het wordt voornamelijk gebruikt om de threads te detecteren die in een impasse zijn geraakt en om er details over te krijgen.

We kunnen de ThreadMxBean-interface gebruiken om de threaddump programmatisch vast te leggen. De methode getThreadMXBean() van ManagementFactory wordt gebruikt om een ​​instantie van de ThreadMXBean-interface op te halen. Het retourneert het aantal live threads van zowel daemon als niet-daemon. ManagementFactory is een fabrieksklasse voor het ophalen van de beheerde bonen voor het Java-platform.

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

Handmatige analyse van draaddumps

Analyse van threaddumps kan erg handig zijn bij het lokaliseren van problemen in multithreaded processen. Problemen zoals deadlocks, lock-conflicten en overmatig CPU-gebruik door individuele threaddumps kunnen worden opgelost door de status van individuele threaddumps te visualiseren.

Maximale doorvoer van de toepassing kan worden bereikt door de status van elke thread te corrigeren na analyse van de threaddump.

Laten we bijvoorbeeld zeggen dat een proces veel CPU gebruikt, we kunnen uitzoeken of een thread de CPU het meest gebruikt. Als er zo’n thread is, converteren we het LWP-nummer naar een hexadecimaal getal. Vervolgens kunnen we vanuit de threaddump de thread vinden met nid gelijk aan het eerder verkregen hexadecimale getal. Met behulp van de stacktracering van de thread kunnen we het probleem lokaliseren. Laten we de proces-ID van de thread achterhalen met behulp van de onderstaande opdracht.

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

[[email protected] ~]# 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

Laten we eens kijken naar het onderstaande stukje threaddump. Gebruik jstack -l 26680 om threaddump voor proces 26680 te krijgen

[[email protected] ~]# 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

Laten we nu eens kijken wat we kunnen onderzoeken met behulp van threaddumps. Als we de threaddump observeren, kunnen we veel inhoud zien, wat overweldigend kan zijn. Als we echter stap voor stap gaan, kan het vrij eenvoudig te begrijpen zijn. Laten we de eerste regel begrijpen

2020-06-27 09:01:29
Volledige threaddump Java HotSpot(TM) 64-bits server-VM (25.221-b11 gemengde modus):

Het bovenstaande geeft de tijd weer waarop de dump is gegenereerd en informatie over de JVM die is gebruikt. Vervolgens kunnen we uiteindelijk de lijst met threads zien, de eerste daarvan is onze ReferenceHandler-thread.

Geblokkeerde threads analyseren

Als we de onderstaande threaddump-logboeken analyseren, kunnen we vaststellen dat er threads met de status GEBLOKKEERD zijn gedetecteerd, waardoor de prestaties van een toepassing erg traag zijn. Dus als we de GEBLOKKEERDE threads kunnen vinden, kunnen we proberen de threads te extraheren die verband houden met de sloten die de threads proberen te verkrijgen. Analyse van de stacktracering van de thread die momenteel het slot vasthoudt, kan helpen bij het oplossen van het probleem.

[[email protected] ~]# 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)
.
.
.
.

Deadlock-thread analyseren

Een andere veelgebruikte toepassing van threaddumps is het detecteren van deadlocks. Het opsporen en oplossen van deadlocks kan een stuk eenvoudiger zijn als we de threaddumps analyseren.

Een deadlock is een situatie waarbij ten minste twee threads betrokken zijn, waarbij de bron die nodig is voor één thread om de uitvoering voort te zetten, wordt vergrendeld door een andere thread en tegelijkertijd wordt de bron die nodig is voor de tweede thread vergrendeld door de eerste thread.

Geen van de threads kan dus doorgaan met uitvoeren, en dit resulteert in een deadlock-situatie en eindigt in het vastlopen van de applicatie. Als er dreadlocks aanwezig zijn, zal het laatste deel van de threaddump de informatie over de deadlock als volgt afdrukken.

"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([email protected]/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([email protected]/Thread.java:844)

Hier kunnen we de deadlock-informatie zien in een redelijk voor mensen leesbaar formaat.

  Hoe maak je een lange kolom in meerdere kolommen in Excel

Afgezien daarvan, als we al het bovenstaande stuk threaddump samenvatten, staat de onderstaande informatie.

  • Reference handler is de voor mensen leesbare naam van de thread.
  • #2 is de unieke id van de thread.
  • daemon geeft aan of de thread een daemon-thread is.
  • De numerieke prioriteit van de thread wordt gegeven door prio=10.
  • De huidige status van de thread wordt aangegeven door te wachten op voorwaarde.
  • Vervolgens zien we de stacktrace, die de vergrendelingsinformatie bevat.

Thread Dumps-analyzers

Naast handmatige analyse zijn er tal van tools beschikbaar voor het analyseren van threaddumps, zowel online als offline. Hieronder staan ​​enkele van de vermelde tools die we kunnen gebruiken op basis van de vereisten.

Laten we eerst eens kijken naar online tools.

#1. Snelle draad

Snelle draad is de favoriete threaddump-analysetool van de DevOps-engineer om complexe productieproblemen op te lossen. Dit is een online Java-threaddumpanalysator. We kunnen de threaddump uploaden als een bestand of we kunnen de threaddump direct kopiëren en plakken.

Afhankelijk van de grootte analyseert het de threaddump en geeft het de informatie weer zoals weergegeven in de schermafbeelding.

Functies

  • Problemen met JVM-crashes, vertragingen, geheugenlekken, bevriezingen, CPU-spikes oplossen
  • Instant RCA (wacht niet op leveranciers)
  • Intuïtief dashboard
  • REST API-ondersteuning
  • Machinaal leren

#2. Spotify Thread Dump-analysator

De Spotify Thread Dump-analysator is gelicentieerd onder versie 2.0 van de Apache-licentie. Het is een online tool en accepteert de threaddump als een bestand of we kunnen de threaddump direct kopiëren en plakken. Afhankelijk van de grootte analyseert het de threaddump en geeft het de informatie weer zoals weergegeven in de schermafbeelding.

#3. Jstack-recensie

Jstack.review analyseert java-threaddumps vanuit de browser. Deze pagina is alleen aan de clientzijde.

#4. Website 24×7

Deze hulpmiddel is een vereiste voor het detecteren van defecte threads die de prestaties van Java Virtual Machine (JVM) verslechteren. Problemen zoals deadlocks, lock-conflicten en overmatig CPU-gebruik door individuele threaddumps kunnen worden opgelost door de status van individuele threaddumps te visualiseren.

Maximale doorvoer van de app kan worden bereikt door de status van elke thread die door de tool wordt geleverd, te corrigeren.

Laten we nu offline tools verkennen.

Als het om profilering gaat, is alleen de beste tool goed genoeg.

#1. JProfiler

JProfiler is een van de meest populaire threaddump-analyseprogramma’s onder Java-ontwikkelaars. De intuïtieve gebruikersinterface van JProfiler helpt u prestatieknelpunten op te lossen, geheugenlekken op te sporen en threading-problemen te begrijpen.

JProfiler ondersteunt profilering op de volgende platformen:

  • ramen
  • macOS
  • Linux
  • FreeBSD
  • Solaris
  • AIX
  • HP-UX

Hieronder staan ​​enkele functies die JProfiler tot de beste keuze maken voor het profileren van onze applicaties op de JVM.

Functies

  • Ondersteunt databaseprofilering voor JDBC, JPA en NoSQL
  • Ondersteuning voor de Java Enterprise-editie is ook beschikbaar
  • Presenteert informatie op hoog niveau over RMI-oproepen
  • Stellaire analyse van geheugenlekken
  • Uitgebreide QA-mogelijkheden
  • De geïntegreerde threadprofiler is nauw geïntegreerd met de CPU-profileringsweergaven.
  • Ondersteuning voor platforms, IDE’s en applicatieservers.

#2. IBM TMDA

IBM Thread and Monitor Dump Analyzer voor Java (TMDA) is een tool waarmee vastlopers, impasses, bronconflicten en knelpunten in Java-threaddumps kunnen worden geïdentificeerd. Het is een IBM-product, maar de TMDA-tool wordt geleverd zonder enige garantie of ondersteuning; ze proberen de tool echter in de loop van de tijd te repareren en te verbeteren.

#3. Beheer Engine

Beheer Engine Application Manager kan helpen bij het bewaken van JVM Heap- en Non-Heap-geheugen. We kunnen zelfs drempels configureren en gewaarschuwd worden via e-mail, sms, enz., en ervoor zorgen dat een Java-toepassing goed is afgestemd.

#4. JouwKit

JouwKit bestaat uit de onderstaande producten genaamd het als een Kit.

  • Java Profiler – Volledig uitgeruste low-overhead profiler voor Java EE- en Java SE-platforms.
  • YouMonitor – Prestatiebewaking en profilering van Jenkins, TeamCity, Gradle, Maven, Ant, JUnit en TestNG.
  • .NET Profiler – Gebruiksvriendelijke prestatie- en geheugenprofiler voor .NET Framework.

Conclusie

Nu weet je hoe thread-dumps nuttig zijn bij het begrijpen en diagnosticeren van problemen in multithreaded applicaties. Met juiste kennismet betrekking tot de threaddumps – hun structuur, de informatie die ze bevatten, enzovoort – kunnen we ze gebruiken om de oorzaken van de problemen snel te identificeren.

gerelateerde berichten