• Erledigen Sie die Anwendungssicherheit auf die richtige Weise! Erkennen, schützen, überwachen, beschleunigen und mehr…
  • Lassen Sie uns über den Thread-Dump sprechen und wie man ihn analysiert.

    Wir werden auch diskutieren, wie es hilft, die Probleme und einige der Analysegeräte, die Sie verwenden können, genau zu bestimmen.

    What is Thread?

    Ein Prozess ist ein Computerprogramm, das in den Arbeitsspeicher des Computers geladen wird und gerade ausgeführt wird. Es kann von einem Prozessor oder einer Reihe von Prozessoren ausgeführt werden. Im Speicher wird ein Prozess mit wichtigen Informationen wie Variablenspeichern, Dateihandles, Programmzähler, Registern und Signalen usw. beschrieben.

    Ein Prozess kann aus vielen so genannten Lightweight-Prozessen bestehen Themen. Dies hilft, Parallelität zu erreichen, bei der ein Prozess in mehrere Threads unterteilt ist. Dies führt zu einer besseren Leistung. Alle Threads innerhalb eines Prozesses teilen sich den gleichen Speicherplatz und sind voneinander abhängig.

    Thread-Dumps

    Wenn der Prozess ausgeführt wird, können wir mithilfe von den aktuellen Ausführungsstatus der Threads im Prozess ermitteln Thread-Dumps. Ein Thread-Dump enthält eine Momentaufnahme aller Threads, die an einem bestimmten Punkt während der Ausführung eines Programms aktiv sind. Es enthält alle relevanten Informationen zum Thread und seinem aktuellen Status.

    Eine moderne Anwendung umfasst heute mehrere Anzahlen von Threads. Jeder Thread benötigt bestimmte Ressourcen und führt bestimmte Aktivitäten im Zusammenhang mit dem Prozess aus. Dies kann die Leistung einer Anwendung steigern, da Threads verfügbare CPU-Kerne verwenden können.

    Es gibt jedoch Kompromisse, z. B. können mehrere Threads manchmal nicht gut aufeinander abgestimmt sein und es kann zu einer Deadlock-Situation kommen. Wenn also etwas schief geht, können wir Thread-Dumps verwenden, um den Status unserer Threads zu überprüfen.

    Thread dump in Java

    Ein JVM-Thread-Dump ist eine Auflistung des Status aller Threads, die zu diesem bestimmten Zeitpunkt Teil des Prozesses sind. Es enthält Informationen zum Stapel des Threads, die als Stapelverfolgung dargestellt werden. Da es im Klartext geschrieben ist, kann der Inhalt zur späteren Überprüfung gespeichert werden. Die Analyse von Thread-Dumps kann dabei helfen

    • Optimierung der JVM-Leistung
    • Optimierung der Anwendungsleistung
    • Diagnose von Problemen, z. B. Deadlock, Thread-Konflikt usw.

    Generation of Thread Dumps

    Es gibt viele Möglichkeiten, Thread-Dumps zu generieren. Im Folgenden finden Sie einige JVM-basierte Tools, die über die Befehlszeile / das Terminal (CLI-Tools) oder das ausgeführt werden können /Behälter Verzeichnis (GUI-Tools) des Installationsordners von Java.

    Lassen Sie uns sie erkunden.

    # 1. jStack

    Der einfachste Weg, einen Thread-Dump zu generieren, ist die Verwendung von jStack. jStack wird mit JVM ausgeliefert und kann über die Befehlszeile verwendet werden. Hier benötigen wir die PID des Prozesses, für den wir den Thread-Dump generieren möchten. Um PID zu erhalten, können wir verwenden jps Befehl wie unten gezeigt.

    jps -l

    jps listet alle Java-Prozess-IDs auf.

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

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

    Wie wir hier sehen können, erhalten wir eine Liste aller laufenden Java-Prozesse. Es enthält die lokale VM-ID für den ausgeführten Java-Prozess und den Namen der Anwendung in den Spalten eins bzw. zwei. Um den Thread-Dump zu generieren, verwenden wir den jStack programmieren mit Es Flag, das eine lange aufgelistete Ausgabe des Dumps erstellt. Wir können die Ausgabe auch an eine Textdatei unserer Wahl weiterleiten.

    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 ist ein GUI-Tool, mit dem wir Java-Anwendungen beheben, überwachen und profilieren können. Es kommt auch mit JVM und kann von der gestartet werden /Behälter Verzeichnis unserer Java-Installation. Es ist sehr intuitiv und einfach zu bedienen. Neben anderen Optionen können wir auch den Thread-Dump für einen bestimmten Prozess erfassen.

    Um den Thread-Dump für einen bestimmten Prozess anzuzeigen, können Sie mit der rechten Maustaste auf das Programm klicken und auswählen Thread-Dump in dem Kontextmenü.

    # 3. jcmd

    JCMD ist ein Befehlszeilenprogramm, das im Lieferumfang des JDK enthalten ist und zum Senden von Diagnosebefehlsanforderungen an die JVM verwendet wird.

    Es funktioniert jedoch nur auf dem lokalen Computer, auf dem die Java-Anwendung ausgeführt wird. Es kann verwendet werden, um Java-Flugaufzeichnungen zu steuern, JVM- und Java-Anwendungen zu diagnostizieren und Fehler zu beheben. Wir können die verwenden Thread.print Befehl von jcmd, um eine Liste der Thread-Dumps für einen bestimmten von der PID angegebenen Prozess abzurufen.

    Nachfolgend finden Sie ein Beispiel für die Verwendung 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 steht für Java-Missionskontrolle. Es ist ein Open-Source-GUI-Tool, das im Lieferumfang von JDK enthalten ist und zum Sammeln und Analysieren von Java-Anwendungsdaten verwendet wird.

    Es kann von der gestartet werden /Behälter Ordner unserer Java-Installation. Java-Administratoren und -Entwickler verwenden das Tool, um detaillierte Informationen auf niedriger Ebene über das Verhalten der JVM und der Anwendung zu sammeln. Es ermöglicht eine detaillierte und effiziente Analyse der von Java gesammelten Daten Flug Rekorder.

    Beim Start jmcsehen wir eine Liste der Java-Prozesse, die auf dem lokalen Computer ausgeführt werden. Eine Fernverbindung ist ebenfalls möglich. Auf einen bestimmten Prozess können wir mit der rechten Maustaste klicken und auswählen Starten Sie die Flugaufzeichnung und überprüfen Sie dann die Thread-Dumps in der Themen Tab.

    # 5. jconsole

    jconsole ist ein Java Management Extension-Tool, das für die Verwaltung und Überwachung von Beschwerden verwendet wird.

    Es gibt auch eine Reihe vordefinierter Operationen für den JMX-Agenten, die der Benutzer ausführen kann. Es ermöglicht dem Benutzer das Erkennen und Analysieren der Stapelverfolgung eines Live-Programms. Es kann von der gestartet werden /Behälter Ordner unserer Java-Installation.

    Verwendung der jconsole GUI-Tool Wir können den Stack-Trace jedes Threads überprüfen, wenn wir ihn mit einem laufenden Java-Prozess verbinden. Dann können wir auf der Registerkarte Thread den Namen aller laufenden Threads sehen. Um einen Deadlock zu erkennen, können wir auf klicken Deadlock erkennen unten rechts im Fenster. Wenn ein Deadlock erkannt wird, wird er in einer neuen Registerkarte angezeigt, andernfalls a Kein Deadlock erkannt wird Angezeigt werden.

    # 6. ThreadMxBean

    ThreadMXBean ist die Schnittstelle für die Verwaltung des Thread-Systems der virtuellen Java-Maschine, die zum Paket java.lang.Management gehört. Es wird hauptsächlich verwendet, um die Threads zu erkennen, die in eine Deadlock-Situation eingetreten sind, und um Details darüber abzurufen.

    Wir können die ThreadMxBean-Schnittstelle verwenden, um den Thread-Dump programmgesteuert zu erfassen. getThreadMXBean() Methode von ManagementFactory wird verwendet, um eine Instanz von zu erhalten ThreadMXBean Schnittstelle. Es gibt die Anzahl der Daemon- und Nicht-Daemon-Live-Threads zurück. ManagementFactory ist eine Factory-Klasse zum Abrufen der verwalteten Beans für die Java-Plattform.

    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

    Die Analyse von Thread-Dumps kann sehr nützlich sein, um Probleme in Multithread-Prozessen zu lokalisieren. Probleme wie Deadlocks, Sperrenkonflikte und übermäßige CPU-Auslastung durch einzelne Thread-Dumps können durch Visualisierung der Status einzelner Thread-Dumps behoben werden.

    Der maximale Durchsatz der Anwendung kann erreicht werden, indem der Status jedes Threads nach der Analyse des Thread-Dumps korrigiert wird.

    Zum BeispielNehmen wir an, ein Prozess verbraucht viel CPU. Wir können herausfinden, ob ein Thread die CPU am meisten nutzt. Wenn es einen solchen Thread gibt, konvertieren wir seine LWP-Nummer in eine Hexadezimalzahl. Dann können wir aus dem Thread-Dump den Thread mit nid finden, der der zuvor erhaltenen Hexadezimalzahl entspricht. Mithilfe der Stapelverfolgung des Threads können wir das Problem lokalisieren. Lassen Sie uns die Prozess-ID des Threads mit dem folgenden Befehl herausfinden.

    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
    

    Werfen wir einen Blick auf den folgenden Teil des Thread-Dumps. Verwenden Sie, um den Thread-Dump für Prozess 26680 abzurufen 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
    

    Nun wollen wir sehen, was wir mit Thread-Dumps untersuchen können. Wenn wir den Thread-Dump beobachten, können wir viele Inhalte sehen, die überwältigend sein können. Wenn wir jedoch Schritt für Schritt vorgehen, kann dies ziemlich einfach zu verstehen sein. Lassen Sie uns die erste Zeile verstehen

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

    Oben wird die Zeit angezeigt, zu der der Speicherauszug generiert wurde, sowie Informationen zu der verwendeten JVM. Als nächstes sehen wir am Ende die Liste der Threads, der erste unter ihnen ist unser ReferenceHandler Faden.

    Blockierte Threads analysieren

    Wenn wir die folgenden Thread-Dump-Protokolle analysieren, können wir feststellen, dass Threads mit erkannt wurden GESPERRT Status, der die Leistung einer Anwendung sehr langsam macht. Also, wenn wir das finden können GESPERRT Threads können wir versuchen, die Threads zu extrahieren, die sich auf die Sperren beziehen, die die Threads zu erhalten versuchen. Die Analyse der Stapelverfolgung des Threads, der derzeit die Sperre hält, kann zur Lösung des Problems beitragen.

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

    Eine andere sehr häufig verwendete Anwendung von Thread-Dumps ist die Erkennung von Deadlocks. Das Erkennen und Lösen von Deadlocks kann viel einfacher sein, wenn wir die Thread-Dumps analysieren.

    Ein Deadlock ist eine Situation mit mindestens zwei Threads, in der die Ressource, die ein Thread benötigt, um die Ausführung fortzusetzen, von einem anderen Thread gesperrt wird und gleichzeitig die vom zweiten Thread benötigte Ressource vom ersten Thread gesperrt wird.

    Daher kann keiner der Threads die Ausführung fortsetzen. Dies führt zu einer Deadlock-Situation und führt dazu, dass die Anwendung hängen bleibt. Wenn Dreadlocks vorhanden sind, werden im letzten Abschnitt des Thread-Dumps die Informationen zum Deadlock wie folgt ausgedruckt.

    "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 können wir die Deadlock-Informationen in einem für Menschen lesbaren Format sehen.

    Abgesehen davon, wenn wir alle oben genannten Teile des Thread-Dumps zusammenfassen, werden die folgenden Informationen angegeben.

    • Referenzhandler ist der für Menschen lesbare Name des Threads.
    • #2 ist die eindeutige ID des Threads.
    • Daemon Gibt an, ob der Thread ein Daemon-Thread ist.
    • Die numerische Priorität des Threads ist gegeben durch prio= 10.
    • Der aktuelle Status des Threads wird mit bezeichnet Warten unter der Bedingung.
    • Dann sehen wir die Stapelverfolgung, die die Sperrinformationen enthält.

    Thread Dumps Analyzers

    Neben der manuellen Analyse stehen zahlreiche Tools zur Online- und Offline-Analyse von Thread-Dumps zur Verfügung. Im Folgenden finden Sie einige der aufgeführten Tools, die wir je nach Anforderung verwenden können.

    Lassen Sie uns zunächst die Online-Tools untersuchen.

    # 1. Schneller Thread

    Schneller Thread ist DevOps Das beliebteste Thread-Dump-Analysetool des Ingenieurs zur Behebung komplexer Produktionsprobleme. Dies ist ein Online-Java-Thread-Dump-Analysator. Wir können den Thread-Dump als Datei hochladen oder den Thread-Dump direkt kopieren und einfügen.

    Abhängig von der Größe wird der Thread-Dump analysiert und die im Screenshot gezeigten Informationen angezeigt.

    Eigenschaften

    • Fehlerbehebung bei JVM-Abstürzen, Verlangsamungen, Speicherlecks, Einfrieren und CPU-Spitzen
    • Sofortige Cinch (nicht auf Anbieter warten)
    • Intuitives Dashboard
    • REST-API-Unterstützung
    • Maschinelles lernen

    # 2. Spotify Thread Dump Analyzer

    Das Spotify Thread Dump Analyzer ist unter Version 2.0 der Apache-Lizenz lizenziert. Es ist ein Online-Tool und akzeptiert den Thread-Dump als Datei, oder wir können den Thread-Dump direkt kopieren und einfügen. Abhängig von der Größe wird der Thread-Dump analysiert und die im Screenshot gezeigten Informationen angezeigt.

    # 3. Jstack Bewertung

    Jstack.rezension analysiert Java-Thread-Dumps im Browser. Diese Seite ist nur clientseitig.

    # 4. Webseite 24 × 7

    Mit diesem Werkzeug ist eine Voraussetzung für die Erkennung fehlerhafter Threads, die die Leistung der Java Virtual Machine (JVM) beeinträchtigen. Probleme wie Deadlocks, Sperrenkonflikte und übermäßige CPU-Auslastung durch einzelne Thread-Dumps können durch Visualisierung der Status einzelner Thread-Dumps behoben werden.

    Der maximale Durchsatz der App kann erreicht werden, indem der Status jedes vom Tool bereitgestellten Threads korrigiert wird.

    Lassen Sie uns nun die Offline-Tools untersuchen.

    Wenn es um die Profilerstellung geht, ist nur das beste Tool gut genug.

    # 1. JProfiler

    JProfiler ist einer der beliebtesten Thread-Dump-Analysatoren unter Java-Entwickler. Die intuitive Benutzeroberfläche von JProfiler hilft Ihnen dabei, Leistungsengpässe zu beheben, Speicherlecks zu beheben und Threading-Probleme zu verstehen.

    JProfiler

    JProfiler unterstützt die Profilerstellung auf folgenden Plattformen:

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

    Im Folgenden sind einige Funktionen aufgeführt, die JProfiler zur ersten Wahl für die Profilerstellung unserer Anwendungen in der JVM machen.

    Eigenschaften

    • Unterstützt Datenbankprofile für JDBC, JPA und NoSQL
    • Unterstützung für Java Enterprise Edition ist ebenfalls verfügbar
    • Bietet allgemeine Informationen zu RMI-Anrufen
    • Sternanalyse von Speicherlecks
    • Umfangreiche QS-Funktionen
    • Der integrierte Thread-Profiler ist eng in die CPU-Profilansichten integriert.
    • Unterstützung für Plattformen, IDEs und Anwendungsserver.

    # 2. IBM TMDA

    IBM Thread and Monitor Dump Analyzer für Java (TMDA) ist ein Tool, mit dem Hangs, Deadlocks, Ressourcenkonflikte und Engpässe in Java-Thread-Dumps identifiziert werden können. Es handelt sich um ein IBM Produkt, das TMDA-Tool wird jedoch ohne Garantie oder Support bereitgestellt. Sie versuchen jedoch, das Tool im Laufe der Zeit zu reparieren und zu verbessern.

    # 3. Manageengine

    Manageengine Der Anwendungsmanager kann bei der Überwachung des JVM-Heap- und Nicht-Heap-Speichers helfen. Wir können sogar Schwellenwerte konfigurieren und per E-Mail, SMS usw. benachrichtigt werden, um sicherzustellen, dass eine Java-Anwendung gut abgestimmt ist.

    # 4. YourKit

    YourKit besteht aus den folgenden Produkten, die als Kit bezeichnet werden.

    • Java Profiler - Voll funktionsfähiger Low Overhead Profiler für Java EE- und Java SE-Plattformen.
    • YouMonitor - Leistungsüberwachung und Profilerstellung von Jenkins, TeamCity, Gradle, Maven, Ant, JUnit und TestNG.
    • .NET Profiler - Einfach zu verwendender Leistungs- und Speicherprofiler für .NET Framework.

    Fazit

    Jetzt wissen Sie, wie nützlich Thread-Dumps sind, um Probleme in Multithread-Anwendungen zu verstehen und zu diagnostizieren. Mit richtig WissenIn Bezug auf die Thread-Dumps - ihre Struktur, die darin enthaltenen Informationen usw. - können wir sie verwenden, um die Ursachen der Probleme schnell zu identifizieren.