Mi az a Thread Dump és hogyan elemezzük őket?

Beszéljünk a szálkiíratásról és annak elemzéséről.

Azt is megvitatjuk, hogy miként segít a problémák pontos meghatározásában, és néhány használható elemzőt.

Mi az a Thread?

A folyamat egy számítógépes program, amely betöltődik a számítógép memóriájába, és végrehajtás alatt áll. Ez végrehajtható processzorral vagy processzorkészlettel. A folyamatot a memóriában írják le olyan fontos információkkal, mint a változótárak, fájlkezelők, programszámláló, regiszterek és jelek stb.

Egy folyamat sok könnyű folyamatból, úgynevezett szálból állhat. Ez segít a párhuzamosság elérésében, ahol egy folyamat több szálra van felosztva. Ez jobb teljesítményt eredményez. A folyamaton belüli összes szál ugyanazon a memóriaterületen osztozik, és függenek egymástól.

Szálkidobások

A folyamat végrehajtása közben szálkiíratások segítségével észlelhetjük a folyamatban lévő szálak végrehajtásának aktuális állapotát. A szálkiíratás pillanatképet tartalmaz a program végrehajtása során egy adott ponton aktív összes szálról. Minden lényeges információt tartalmaz a szálról és annak aktuális állapotáról.

Egy mai modern alkalmazás több szálat foglal magában. Minden szál bizonyos erőforrásokat igényel, bizonyos, a folyamathoz kapcsolódó tevékenységeket végez. Ez növelheti egy alkalmazás teljesítményét, mivel a szálak felhasználhatják a rendelkezésre álló CPU magokat.

De vannak kompromisszumok, például előfordulhat, hogy több szál nem koordinál jól egymással, és holtpont alakulhat ki. Tehát, ha valami elromlik, szálkiíratással ellenőrizhetjük szálaink állapotát.

Szálkiíratás Java nyelven

A JVM szálkiíratása a folyamat részét képező összes szál állapotának listája az adott időpontban. Információkat tartalmaz a szál vereméről, veremnyomként jelenítve meg. Mivel ez egyszerű szöveggel van írva, a tartalom elmenthető későbbi áttekintés céljából. A szálkidobások elemzése segíthet

  • A JVM teljesítményének optimalizálása
  • Az alkalmazás teljesítményének optimalizálása
  • Problémák diagnosztizálása, pl. holtpont, szálak vitája stb.

Menetlerakók generálása

Számos módja van a szálkiíratok létrehozásának. Az alábbiakban néhány JVM-alapú eszköz található, amelyek a Java telepítési mappájának parancssorból/termináljából (CLI-eszközök) vagy a /bin (GUI-eszközök) könyvtárból futtathatók.

Fedezzük fel őket.

#1. jStack

A szálkiíratást a legegyszerűbben a jStack használatával hozhatja létre. A jStack JVM-mel érkezik, és a parancssorból használható. Itt szükségünk van annak a folyamatnak a PID-jére, amelyhez a szálkiíratást szeretnénk előállítani. A PID lekéréséhez használhatjuk a jps parancsot az alábbiak szerint.

jps -l

A jps felsorolja az összes java folyamatazonosítót.

Windows rendszeren

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

Linuxon

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

Amint itt láthatjuk, kapunk egy listát az összes futó Java folyamatról. Tartalmazza a futó Java-folyamat helyi virtuálisgép-azonosítóját és az alkalmazás nevét az első, illetve a második oszlopban. Most a szálkiíratáshoz a jStack programot használjuk –l kapcsolóval, amely a kiíratás hosszú listás kimenetét hozza létre. A kimenetet egy általunk választott szövegfájlba is átvezethetjük.

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. jvisuavm

A Jvisualvm egy grafikus felhasználói felület, amely segít a Java-alkalmazások hibaelhárításában, megfigyelésében és profiljában. JVM-mel is érkezik, és a java telepítésünk /bin könyvtárából indítható. Nagyon intuitív és könnyen használható. Többek között azt is lehetővé teszi, hogy rögzítsük a szálkiíratást egy adott folyamathoz.

Egy adott folyamat szálkiíratásának megtekintéséhez kattintson a jobb gombbal a programra, és válassza a Szálkiíratást a helyi menüből.

#3. jcmd

A JCMD egy parancssori segédprogram, amely a JDK-val együtt kerül szállításra, és diagnosztikai parancskérések küldésére szolgál a JVM-nek.

  Érdemes megvenni az Apple Watch 4-et?

Ez azonban csak azon a helyi gépen működik, amelyen a Java alkalmazás fut. Használható Java Flight Recordings vezérlésére, JVM és Java alkalmazások diagnosztizálására és hibaelhárítására. Használhatjuk a jcmd Thread.print parancsát, hogy megkapjuk a PID által meghatározott folyamathoz tartozó szálkiíratok listáját.

Az alábbiakban egy példa látható a jcmd használatára.

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

A JMC a Java Mission Control rövidítése. Ez egy nyílt forráskódú grafikus felhasználói felület, amely a JDK-val együtt kerül forgalomba, és a Java alkalmazások adatainak gyűjtésére és elemzésére szolgál.

A Java telepítésünk /bin mappájából indítható. A Java rendszergazdák és fejlesztők az eszköz segítségével részletes, alacsony szintű információkat gyűjtenek a JVM és az alkalmazások viselkedéséről. Lehetővé teszi a Java Flight Recorder által gyűjtött adatok részletes és hatékony elemzését.

A jmc elindításakor láthatjuk a helyi gépen futó Java folyamatok listáját. Távoli kapcsolat is lehetséges. Egy adott folyamatnál jobb gombbal kattinthatunk, és kiválaszthatjuk a Repülésrögzítés indítása lehetőséget, majd ellenőrizhetjük a szálkiíratásokat a Szálak lapon.

#5. jconsole

A jconsole egy Java Management Extension eszköz, amelyet panaszkezelésre és -figyelésre használnak.

Ezenkívül rendelkezik előre meghatározott műveletekkel a JMX ügynökön, amelyeket a felhasználó végrehajthat. Lehetővé teszi a felhasználó számára egy élő program veremnyomának észlelését és elemzését. A Java telepítésünk /bin mappájából indítható.

  Hogyan férhetek hozzá az Epic Games fiókomhoz

A jconsole GUI eszköz segítségével ellenőrizhetjük az egyes szálak veremnyomait, amikor egy futó Java folyamathoz kapcsoljuk. Ezután a Szál lapon láthatjuk az összes futó szál nevét. A holtpont észleléséhez kattintson a Detect Deadlock gombra az ablak jobb alsó sarkában. Ha a rendszer holtpontot észlel, az egy új lapon jelenik meg, különben a Nincs holtpont észlelve üzenet jelenik meg.

#6. ThreadMxBean

A ThreadMXBean a java.lang.Management csomaghoz tartozó Java virtuális gép szálrendszerének kezelési felülete. Főleg a holtpontba került szálak észlelésére és részletek megszerzésére szolgál.

A ThreadMxBean felület segítségével programozottan rögzíthetjük a szálkiíratást. A ManagementFactory getThreadMXBean() metódusa a ThreadMXBean felület példányának beszerzésére szolgál. Mind a démonos, mind a nem démonos élő szálak számát adja vissza. A ManagementFactory egy gyári osztály a felügyelt komponensek Java platformhoz való beszerzéséhez.

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

Menetlerakók kézi elemzése

A szálkiíratok elemzése nagyon hasznos lehet a többszálú folyamatok problémáinak pontos meghatározásában. Az olyan problémák, mint például a holtpontok, a zárolási versengés és az egyes szálkiíratások által okozott többlet CPU-kihasználás, megoldhatók az egyes szálkiíratok állapotának megjelenítésével.

Az alkalmazás maximális átviteli sebessége az egyes szálak állapotának a szálkiíratás elemzése utáni javításával érhető el.

Például, ha egy folyamat sok CPU-t használ, megtudhatjuk, hogy valamelyik szál használja-e a legtöbb CPU-t. Ha van ilyen szál, akkor az LWP-számát hexadecimális számmá alakítjuk. Ekkor a szálkiíratásból megtaláljuk azt a szálat, amelynek nidje megegyezik az előzőleg kapott hexadecimális számmal. A szál veremnyomának segítségével pontosan meghatározhatjuk a problémát. Nézzük meg a szál folyamatazonosítóját az alábbi paranccsal.

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

Vessünk egy pillantást az alábbi szálkidobás-darabra. A 26680-as folyamat szálkiíratásához használja a jstack -l 26680 parancsot

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

Most pedig lássuk, melyek azok a dolgok, amelyeket felfedezhetünk a szálkiíratok használatával. Ha megfigyeljük a szálkidobást, sok tartalmat láthatunk, ami lehengerlő lehet. Ha azonban egyszerre csak egy lépést teszünk, akkor ez meglehetősen egyszerű lehet. Értsük meg az első sort

2020-06-27 09:01:29
Teljes szál kiíratása Java HotSpot(TM) 64 bites szerver virtuális gép (25.221-b11 vegyes mód):

A fenti a dump létrehozásának idejét és a használt JVM-re vonatkozó információkat jeleníti meg. Ezután a végén láthatjuk a szálak listáját, ezek közül az első a ReferenceHandler szálunk.

Blokkolt szálak elemzése

Ha elemezzük az alábbi szálkiíratási naplókat, azt találjuk, hogy BLOKKOLVA állapotú szálakat észlelt, ami nagyon lelassítja az alkalmazás teljesítményét. Tehát, ha megtaláljuk a BLOCKED szálakat, akkor megpróbálhatjuk kivonni azokat a szálakat, amelyek azokhoz a zárakhoz kapcsolódnak, amelyeket a szálak megpróbálnak megszerezni. A zárat jelenleg tartó szál veremnyomának elemzése segíthet a probléma megoldásában.

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

Elakadt szál elemzése

A szálkidobások másik nagyon gyakran használt alkalmazása a holtpontok észlelése. A holtpontok észlelése és megoldása sokkal könnyebb lehet, ha elemezzük a szálkidobásokat.

A holtpont olyan helyzet, amely legalább két szálat érint, ahol az egyik szál által a végrehajtás folytatásához szükséges erőforrást egy másik szál zárolja, és ugyanakkor a második szál által igényelt erőforrást az első szál zárolja.

  Gomb javítása az Xbox One kontrolleren

Tehát egyik szál sem tudja folytatni a végrehajtást, és ez holtponthoz vezet, és az alkalmazás elakadásához vezet. Ha raszta van jelen, akkor a szálkiíratás utolsó része az alábbiak szerint nyomtatja ki a holtpontra vonatkozó információkat.

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

Itt láthatjuk a holtpontról szóló információkat ember számára meglehetősen olvasható formátumban.

Ettől eltekintve, ha összeadjuk a fenti szálkiíratási darabot, akkor az alábbi információkat tartalmazza.

  • A hivatkozáskezelő a szál ember által olvasható neve.
  • #2 a szál egyedi azonosítója.
  • A démon azt jelzi, hogy a szál démonszál-e.
  • A szál numerikus prioritását a prio=10 adja meg.
  • A szál aktuális állapotát a feltételre várakozás jelöli.
  • Ezután látjuk a verem nyomát, amely tartalmazza a zárolási információkat.

Menetlerakók elemzők

A kézi elemzés mellett számos eszköz áll rendelkezésre a szálkiíratok elemzésére, online és offline egyaránt. Az alábbiakban felsorolunk néhányat a felsorolt ​​eszközök közül, amelyeket az igények alapján tudunk használni.

Először is nézzük meg az online eszközöket.

#1. Gyors szál

Gyors szál a DevOps mérnök kedvenc szálkiíratási elemző eszköze az összetett gyártási problémák hibaelhárítására. Ez egy online Java szálkiíratási elemző, feltölthetjük a szálkiíratást fájlként, vagy közvetlenül másolhatjuk és beilleszthetjük a szálkiíratást.

A mérettől függően elemzi a szálkiíratást, és megjeleníti az információkat a képernyőképen látható módon.

Jellemzők

  • JVM-összeomlások, lassulások, memóriaszivárgások, lefagyások, CPU-csúcsok hibaelhárítása
  • Azonnali RCA (ne várja meg a szállítókat)
  • Intuitív irányítópult
  • REST API támogatás
  • Gépi tanulás

#2. Spotify Thread Dump Analyzer

Az Spotify Thread Dump Analyzer az Apache licenc 2.0-s verziója alatt van licencelve. Ez egy online eszköz, és a szálkiíratást fájlként fogadja el, vagy közvetlenül másolhatjuk és beilleszthetjük a szálkiíratást. A mérettől függően elemzi a szálkiíratást, és megjeleníti az információkat a képernyőképen látható módon.

#3. Jstack áttekintés

Jstack.review elemzi a Java szálkiíratásokat a böngészőn belül. Ez az oldal csak ügyféloldali.

#4. Oldal 24×7

Ez eszköz előfeltétele a Java Virtual Machine (JVM) teljesítményét rontó hibás szálak észlelésének. Az olyan problémák, mint például a holtpontok, a zárolási versengés és az egyes szálkiíratások által okozott többlet CPU-kihasználás, megoldhatók az egyes szálkiíratok állapotának megjelenítésével.

Az alkalmazás maximális átviteli sebessége az eszköz által biztosított egyes szálak állapotának javításával érhető el.

Most pedig fedezzük fel az offline eszközöket.

Ha profilalkotásról van szó, csak a legjobb eszköz elég jó.

#1. JProfiler

JProfiler az egyik legnépszerűbb szálkiíratási elemző a Java fejlesztők körében. A JProfiler intuitív felhasználói felülete segít a teljesítménybeli szűk keresztmetszetek megoldásában, a memóriaszivárgások felderítésében és a szálkezelési problémák megértésében.

A JProfiler a következő platformokon támogatja a profilalkotást:

  • ablakok
  • Mac operációs rendszer
  • Linux
  • FreeBSD
  • Solaris
  • AIX
  • HP-UX

Az alábbiakban felsorolunk néhány olyan funkciót, amelyek miatt a JProfiler a legjobb választás az alkalmazásaink JVM-en való profilálásához.

Jellemzők

  • Támogatja a JDBC, JPA és NoSQL adatbázis-profilozást
  • A Java Enterprise Edition támogatása is elérhető
  • Magas szintű információkat nyújt az RMI-hívásokról
  • Memóriaszivárgások csillagelemzése
  • Széleskörű minőségbiztosítási képességek
  • Az integrált menetprofilozó szorosan integrálva van a CPU profilozási nézeteivel.
  • Platformok, IDE-k és alkalmazáskiszolgálók támogatása.

#2. IBM TMDA

IBM Thread and Monitor Dump Analyzer for Java (TMDA) egy olyan eszköz, amely lehetővé teszi a lefagyások, a holtpontok, az erőforrásokkal kapcsolatos viták és a szűk keresztmetszetek azonosítását a Java szálkiíratásaiban. Ez egy IBM termék, de a TMDA eszközt garancia vagy támogatás nélkül biztosítjuk; azonban idővel megpróbálják javítani és javítani az eszközt.

#3. ManageEngine

ManageEngine Az alkalmazáskezelő segíthet a JVM Heap és Non-Heap memória figyelésében. Még a küszöbértékeket is beállíthatjuk, és e-mailben, SMS-ben stb. kaphatunk figyelmeztetést, és gondoskodhatunk arról, hogy a Java-alkalmazások megfelelően hangoljanak.

#4. YourKit

YourKit az alábbi, készletnek nevezett termékekből áll.

  • Java Profiler – Teljes értékű alacsony költségű profilozó Java EE és Java SE platformokhoz.
  • YouMonitor – Jenkins, TeamCity, Gradle, Maven, Ant, JUnit és TestNG teljesítményfigyelése és profilalkotása.
  • .NET Profiler – Könnyen használható teljesítmény- és memóriaprofilozó a .NET keretrendszerhez.

Következtetés

Most már tudja, hogy a szálkiíratok mennyire hasznosak a többszálú alkalmazások problémáinak megértésében és diagnosztizálásában. Megfelelővel tudása cérnadömpingekkel kapcsolatban – azok felépítését, a bennük lévő információkat stb. – a problémák okainak gyors azonosítására tudjuk felhasználni.