Hvad er Thread Dump, og hvordan analyserer man dem?

Lad os tale om tråddumpet, og hvordan man analyserer det.

Vi vil også diskutere, hvordan det hjælper med at lokalisere problemerne og nogle af de analyser, du kan bruge.

Hvad er tråd?

En proces er et computerprogram, som indlæses i computerens hukommelse og er under udførelse. Det kan udføres af en processor eller et sæt processorer. En proces er beskrevet i hukommelsen med vigtig information såsom variable lagre, filhåndtag, programtælleren, registre og signaler og så videre.

En proces kan bestå af mange letvægtsprocesser kaldet tråde. Dette hjælper med at opnå parallelitet, hvor en proces er opdelt i flere tråde. Dette resulterer i bedre ydeevne. Alle tråde i en proces deler den samme hukommelsesplads og er afhængige af hinanden.

Tråddumper

Når processen udføres, kan vi registrere den aktuelle tilstand for udførelse af trådene i processen ved hjælp af tråddumps. En tråddump indeholder et øjebliksbillede af alle tråde, der er aktive på et bestemt tidspunkt under afviklingen af ​​et program. Den indeholder alle relevante oplysninger om tråden og dens nuværende tilstand.

En moderne applikation i dag involverer flere antal tråde. Hver tråd kræver visse ressourcer, udfører visse aktiviteter relateret til processen. Dette kan øge ydeevnen af ​​en applikation, da tråde kan bruge tilgængelige CPU-kerner.

Men der er afvejninger, f.eks. kan flere tråde nogle gange ikke koordinere godt med hinanden, og der kan opstå en dødvande. Så hvis noget går galt, kan vi bruge tråddumps til at inspicere tilstanden af ​​vores tråde.

Tråddump i Java

En JVM-tråddump er en liste over tilstanden for alle tråde, der er en del af processen på det pågældende tidspunkt. Den indeholder information om trådens stak, præsenteret som et stakspor. Som det er skrevet i klartekst, kan indholdet gemmes til senere gennemgang. Analyse af tråddumps kan hjælpe

  • Optimering af JVM-ydelse
  • Optimering af applikationsydelse
  • Diagnosticering af problemer, f.eks. dødvande, trådstridigheder osv.

Generering af tråddumps

Der er mange måder at generere tråddumps på. Nedenfor er nogle JVM-baserede værktøjer og kan udføres fra kommandolinjen/terminalen (CLI-værktøjer) eller mappen /bin (GUI-værktøjer) i installationsmappen til Java.

Lad os udforske dem.

#1. jStack

Den enkleste måde at generere et tråddump på er ved at bruge jStack. jStack leveres med JVM og kan bruges fra kommandolinjen. Her har vi brug for PID’en for den proces, som vi ønsker at generere tråddumpet til. For at få PID kan vi bruge jps kommando som vist nedenfor.

jps -l

jps viser alle java-proces-id’er.

På Windows

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

På 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] ~]#

Som vi kan se her, får vi en liste over alle kørende java-processer. Den indeholder det lokale VM-id for den kørende java-proces og navnet på applikationen i henholdsvis kolonne et og to. Nu, for at generere tråddumpet, bruger vi jStack-programmet med -l-flag, som opretter en lang listet output af dumpen. Vi kan også overføre outputtet til en tekstfil efter eget valg.

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 er et GUI-værktøj, der hjælper os med at fejlfinde, overvåge og profilere Java-applikationer. Den leveres også med JVM og kan startes fra mappen /bin i vores java-installation. Det er meget intuitivt og nemt at bruge. Blandt andre muligheder giver det os også mulighed for at fange tråddump for en bestemt proces.

  Sådan får du adgang til tilgængelighedskontrol fra menulinjen og kontrolcenteret på Mac

For at se tråddumpen for en bestemt proces kan vi højreklikke på programmet og vælge tråddump fra kontekstmenuen.

#3. jcmd

JCMD er et kommandolinjeværktøj, der leveres med JDK og bruges til at sende diagnostiske kommandoanmodninger til JVM.

Det virker dog kun på den lokale maskine, hvor Java-applikationen kører. Den kan bruges til at styre Java Flight Recordings, diagnosticere og fejlfinde JVM- og Java-applikationer. Vi kan bruge kommandoen Thread.print i jcmd til at få en liste over tråddumps for en bestemt proces specificeret af PID.

Nedenfor er et eksempel på, hvordan vi kan bruge jcmd.

jcmd 28036 Thread.print

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 står for Java Mission Control. Det er et open source GUI-værktøj, der leveres med JDK og bruges til at indsamle og analysere Java-applikationsdata.

Den kan startes fra mappen /bin i vores Java-installation. Java-administratorer og -udviklere bruger værktøjet til at indsamle detaljerede oplysninger på lavt niveau om JVM’ens og applikationens adfærd. Det muliggør detaljeret og effektiv analyse af data indsamlet af Java Flight Recorder.

Ved lancering af jmc kan vi se en liste over java-processer, der kører på den lokale maskine. En fjernforbindelse er også mulig. På en bestemt proces kan vi højreklikke og vælge Start flyoptagelse og derefter kontrollere tråddumps på fanen Tråde.

#5. jconsole

jconsole er et Java Management Extension-værktøj, der bruges til klagehåndtering og overvågning.

Den har også et sæt foruddefinerede operationer på JMX-agenten, som brugeren kan udføre. Det gør det muligt for brugeren at detektere og analysere stakspor af et live-program. Den kan startes fra mappen /bin i vores Java-installation.

  Hvad er RAM? Alt hvad du behøver at vide

Ved at bruge jconsole GUI-værktøjet kan vi inspicere hver tråds stakspor, når vi forbinder det til en kørende java-proces. Derefter kan vi på fanen Tråd se navnet på alle løbende tråde. For at opdage en dødlås, kan vi klikke på Opdag dødlås nederst til højre i vinduet. Hvis der registreres en deadlock, vil den vises i en ny fane, ellers vil der blive vist et No Deadlock Detected.

#6. ThreadMxBean

ThreadMXBean er grænsefladen til styring af trådsystemet på den virtuelle Java-maskine, der tilhører java.lang.Management-pakken. Det bruges hovedsageligt til at opdage de tråde, der er kommet ind i en dødvande situation og få detaljer om dem.

Vi kan bruge ThreadMxBean-grænsefladen til programmatisk at fange tråddumpet. getThreadMXBean()-metoden fra ManagementFactory bruges til at få en forekomst af ThreadMXBean-grænsefladen. Det returnerer antallet af live-tråde fra både dæmoner og ikke-dæmoner. ManagementFactory er en fabriksklasse til at få de administrerede bønner til Java-platformen.

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

Manuel analyse af tråddumps

Analyse af tråddumps kan være meget nyttig til at lokalisere problemer i flertrådede processer. Problemer som deadlocks, låsestrid og overdreven CPU-udnyttelse af individuelle tråddumps kan løses ved at visualisere tilstandene for individuelle tråddumps.

Maksimal gennemstrømning fra applikationen kan opnås ved at korrigere status for hver tråd efter at have analyseret tråddumpet.

Lad os f.eks. sige, at en proces bruger meget CPU, vi kan finde ud af, om en hvilken som helst tråd bruger CPU’en mest. Hvis der er en sådan tråd, konverterer vi dens LWP-nummer til et hexadecimalt tal. Så fra tråddumpen kan vi finde tråden med nid svarende til det tidligere opnåede hexadecimale tal. Ved at bruge trådens stakspor kan vi lokalisere problemet. Lad os finde ud af proces-id’et for tråden ved hjælp af nedenstående kommando.

ps -mo pid,lwp,stime,tid,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

Lad os tage et kig på nedenstående del af tråddump. For at få tråddump til proces 26680 skal du bruge jstack -l 26680

[[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

Lad os nu se, hvad er de ting, vi kan udforske ved hjælp af tråddumps. Hvis vi observerer tråddumpet, kan vi se en masse indhold, hvilket kan være overvældende. Men hvis vi tager et skridt ad gangen, kan det være ret nemt at forstå. Lad os forstå den første linje

27-06-2020 09:01:29
Fuldtrådsdump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 blandet tilstand):

Ovenstående viser det tidspunkt, hvor dumpet blev genereret, og information om den JVM, der blev brugt. Dernæst kan vi i sidste ende se listen over tråde, den første blandt dem er vores ReferenceHandler-tråd.

Analyse af blokerede tråde

Hvis vi analyserer nedenstående tråddump-logfiler, kan vi opdage, at den har registreret tråde med BLOKERET-status, hvilket gør en applikations ydeevne meget langsom. Så hvis vi kan finde de BLOKKEREDE tråde, kan vi prøve at udtrække trådene relateret til de låse, som trådene forsøger at opnå. Analyse af stak-sporet fra den tråd, der i øjeblikket holder låsen, kan hjælpe med at løse problemet.

[[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)
.
.
.
.

Analyserer fastlåst tråd

En anden meget almindeligt anvendt anvendelse af tråddump er detektering af deadlocks. Detektionen og løsningen af ​​deadlocks kan være meget nemmere, hvis vi analyserer tråddumpene.

  Fix Computer Stuck on Lader dig forbinde til et netværk

En deadlock er en situation, der involverer mindst to tråde, hvor den ressource, der kræves af en tråd for at fortsætte eksekveringen, er låst af en anden tråd, og samtidig er den ressource, der kræves af den anden tråd, låst af den første tråd.

Så ingen af ​​trådene kan fortsætte eksekveringen, og dette resulterer i en deadlock-situation og ender i, at applikationen sætter sig fast. Hvis der er dreadlocks, vil den sidste del af tråddumpen udskrive oplysningerne om deadlock som følger.

"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)

Her kan vi se deadlock-informationen i et ret menneskeligt læsbart format.

Bortset fra dette, hvis vi opsummerer alle ovenstående stykker tråddump sammen, så angiver det nedenstående information.

  • Referencebehandler er trådens navn, der kan læses af mennesker.
  • #2 er trådens unikke id.
  • daemon angiver, om tråden er en dæmontråd.
  • Trådens numeriske prioritet er givet af prio=10.
  • Den aktuelle status for tråden er angivet ved at vente på betingelse.
  • Så ser vi stak-sporet, som inkluderer låseinformationen.

Tråd Dumps Analyzere

Udover manuel analyse er der adskillige værktøjer til rådighed til at analysere tråddumps, både online og offline. Nedenfor er nogle af de listede værktøjer, som vi kan bruge ud fra kravene.

Lad os først udforske onlineværktøjer.

#1. Hurtig tråd

Hurtig tråd er DevOps-ingeniørens foretrukne tråddump-analyseværktøj til fejlfinding af komplekse produktionsproblemer. Dette er en online Java-tråddump-analysator, vi kan uploade tråddumpet som en fil, eller vi kan direkte kopiere og indsætte tråddumpet.

Afhængigt af størrelsen vil den analysere tråddumpen og vise oplysningerne som vist på skærmbilledet.

Funktioner

  • Fejlfinding af JVM-nedbrud, opbremsninger, hukommelseslækager, fryser, CPU-spidser
  • Øjeblikkelig RCA (vent ikke på leverandører)
  • Intuitivt instrumentbræt
  • REST API-understøttelse
  • Maskinelæring

#2. Spotify Thread Dump Analyzer

Det Spotify Thread Dump Analyzer er licenseret under version 2.0 af Apache-licensen. Det er et onlineværktøj og accepterer tråddumpet som en fil, eller vi kan direkte kopiere og indsætte tråddumpet. Afhængigt af størrelsen vil den analysere tråddumpen og vise oplysningerne som vist på skærmbilledet.

#3. Jstack anmeldelse

Jstack.anmeldelse analyserer java-tråddumps fra browseren. Denne side er kun klientsiden.

#4. Site 24×7

Dette værktøj er en forudsætning for at opdage defekte tråde, der forringer Java Virtual Machine (JVM) ydeevne. Problemer som deadlocks, låsestrid og overdreven CPU-udnyttelse af individuelle tråddumps kan løses ved at visualisere tilstandene for individuelle tråddumps.

Maksimal gennemstrømning fra appen kan opnås ved at rette op på status for hver tråd, der leveres af værktøjet.

Lad os nu udforske offlineværktøjer.

Når det kommer til profilering, er kun det bedste værktøj godt nok.

#1. JProfiler

JProfiler er en af ​​de mest populære tråddump-analysatorer blandt Java-udviklere. JProfilers intuitive brugergrænseflade hjælper dig med at løse ydeevneflaskehalse, fastlægge hukommelseslækager og forstå trådningsproblemer.

JProfiler understøtter profilering på følgende platforme:

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

Nedenfor er nogle funktioner, der gør JProfiler til det bedste valg til profilering af vores applikationer på JVM.

Funktioner

  • Understøtter databaseprofilering til JDBC, JPA og NoSQL
  • Support til Java Enterprise Edition er også tilgængelig
  • Præsenterer information på højt niveau om RMI-opkald
  • Stjerneanalyse af hukommelseslækager
  • Omfattende QA-funktioner
  • Den integrerede gevindprofiler er tæt integreret med CPU-profileringsvisningerne.
  • Understøttelse af platforme, IDE’er og applikationsservere.

#2. IBM TMDA

IBM Thread and Monitor Dump Analyzer til Java (TMDA) er et værktøj, der tillader identifikation af hængninger, dødvande, ressourcestrid og flaskehalse i Java-tråddumps. Det er et IBM-produkt, men TMDA-værktøjet leveres som uden nogen garanti eller support; dog forsøger de at reparere og forbedre værktøjet over tid.

#3. Administrer Engine

Administrer Engine Applications Manager kan hjælpe med at overvåge JVM Heap og Non-Heap hukommelse. Vi kan endda konfigurere tærskler og blive advaret via e-mail, SMS osv. og sikre, at en Java-applikation er indstillet godt.

#4. DitKit

DitKit består af nedenstående produkter kaldet det som et sæt.

  • Java Profiler – Fuldt udstyret lav overhead profiler til Java EE og Java SE platforme.
  • YouMonitor – Ydeevneovervågning og profilering af Jenkins, TeamCity, Gradle, Maven, Ant, JUnit og TestNG.
  • .NET Profiler – Nem at bruge ydeevne og hukommelsesprofiler til .NET framework.

Konklusion

Nu ved du, hvordan tråddumps er nyttige til at forstå og diagnosticere problemer i flertrådede applikationer. Med ordentlig videnvedrørende tråddumperne – deres struktur, informationerne i dem og så videre – kan vi bruge dem til hurtigt at identificere årsagerne til problemerne.