Apa itu Thread Dump dan Bagaimana Menganalisisnya?

Mari kita bicara tentang thread dump, dan cara menganalisisnya.

Kami juga akan membahas bagaimana membantu untuk menentukan masalah dan beberapa penganalisa yang dapat Anda gunakan.

Apa itu Benang?

Suatu proses adalah program komputer yang dimuat ke dalam memori komputer dan sedang dieksekusi. Itu dapat dijalankan oleh prosesor atau satu set prosesor. Suatu proses dijelaskan dalam memori dengan informasi penting seperti penyimpanan variabel, pegangan file, penghitung program, register, dan, sinyal, dan sebagainya.

Suatu proses dapat terdiri dari banyak proses ringan yang disebut thread. Ini membantu mencapai paralelisme di mana suatu proses dibagi menjadi beberapa utas. Ini menghasilkan kinerja yang lebih baik. Semua utas dalam suatu proses berbagi ruang memori yang sama dan saling bergantung satu sama lain.

Thread Dump

Saat proses dieksekusi, kami dapat mendeteksi status eksekusi thread saat ini dalam proses menggunakan dump thread. Thread Dump berisi snapshot dari semua thread yang aktif pada titik tertentu selama eksekusi suatu program. Ini berisi semua informasi yang relevan tentang utas dan statusnya saat ini.

Aplikasi modern saat ini melibatkan banyak utas. Setiap utas membutuhkan sumber daya tertentu, melakukan aktivitas tertentu yang terkait dengan proses. Ini dapat meningkatkan kinerja aplikasi karena utas dapat menggunakan inti CPU yang tersedia.

Tapi ada trade-off, misalnya, kadang-kadang banyak utas mungkin tidak berkoordinasi dengan baik satu sama lain dan situasi kebuntuan mungkin muncul. Jadi, jika terjadi kesalahan, kita dapat menggunakan thread dump untuk memeriksa status thread kita.

Pembuangan utas di Jawa

Dump utas JVM adalah daftar status semua utas yang merupakan bagian dari proses pada titik waktu tertentu. Ini berisi informasi tentang tumpukan utas, disajikan sebagai jejak tumpukan. Karena ditulis dalam teks biasa, isinya dapat disimpan untuk ditinjau nanti. Analisis dump thread dapat membantu

  • Mengoptimalkan kinerja JVM
  • Mengoptimalkan kinerja aplikasi
  • Mendiagnosis masalah, misalnya kebuntuan, pertikaian utas, dll.

Generasi Thread Dump

Ada banyak cara untuk menghasilkan dump thread. Di bawah ini adalah beberapa alat berbasis JVM dan dapat dijalankan dari baris perintah/terminal (alat CLI) atau direktori /bin (alat GUI) dari folder instalasi Java.

Mari jelajahi mereka.

#1. jStack

Cara paling sederhana untuk menghasilkan thread dump adalah dengan menggunakan jStack. jStack dikirimkan dengan JVM dan dapat digunakan dari baris perintah. Di sini, kami memerlukan PID dari proses yang ingin kami buat thread dump-nya. Untuk mendapatkan PID kita bisa menggunakan perintah jps seperti gambar di bawah ini.

jps -l

jps mencantumkan semua id proses java.

Di Windows

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

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

Seperti yang bisa kita lihat di sini, kita mendapatkan daftar semua proses java yang sedang berjalan. Ini berisi id VM lokal untuk menjalankan proses java dan nama aplikasi masing-masing di kolom satu dan dua. Sekarang, untuk menghasilkan dump thread, kami menggunakan program jStack dengan flag –l yang membuat output dump yang sudah lama terdaftar. Kami juga dapat mem-pipe output ke beberapa file teks pilihan kami.

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 adalah alat GUI yang membantu kami memecahkan masalah, memantau, dan membuat profil aplikasi Java. Itu juga dilengkapi dengan JVM dan dapat diluncurkan dari direktori /bin instalasi java kami. Ini sangat intuitif dan mudah digunakan. Di antara opsi lainnya, ini juga memungkinkan kami menangkap thread dump untuk proses tertentu.

  Perbaiki Apple TV Remote Tidak Berfungsi

Untuk melihat dump thread untuk proses tertentu, kita dapat mengklik kanan pada program dan memilih Thread Dump dari menu konteks.

#3. jcmd

JCMD adalah utilitas baris perintah yang dikirimkan bersama JDK dan digunakan untuk mengirim permintaan perintah diagnostik ke JVM.

Namun itu hanya berfungsi pada mesin lokal tempat aplikasi Java berjalan. Ini dapat digunakan untuk mengontrol Rekaman Penerbangan Java, mendiagnosis dan memecahkan masalah aplikasi JVM dan Java. Kita dapat menggunakan perintah Thread.print dari jcmd untuk mendapatkan daftar dump thread untuk proses tertentu yang ditentukan oleh PID.

Di bawah ini adalah contoh bagaimana kita dapat menggunakan jcmd.

jcmd 28036 Utas.cetak

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 adalah singkatan dari Java Mission Control. Ini adalah alat GUI sumber terbuka yang disertakan dengan JDK dan digunakan untuk mengumpulkan dan menganalisis data aplikasi java.

Itu dapat diluncurkan dari folder /bin dari instalasi Java kami. Administrator dan pengembang Java menggunakan alat ini untuk mengumpulkan informasi tingkat rendah yang mendetail tentang perilaku JVM dan aplikasi. Ini memungkinkan analisis data yang terperinci dan efisien yang dikumpulkan oleh Java Flight Recorder.

Saat meluncurkan jmc, kita dapat melihat daftar proses java yang berjalan di mesin lokal. Koneksi jarak jauh juga dimungkinkan. Pada proses tertentu, kita dapat mengklik kanan dan memilih Mulai Perekaman Penerbangan lalu memeriksa thread dumps di tab Threads.

#5. jconsole

jconsole adalah alat Ekstensi Manajemen Java yang digunakan untuk manajemen dan pemantauan keluhan.

Ini juga memiliki serangkaian operasi yang telah ditentukan sebelumnya pada agen JMX yang dapat dilakukan pengguna. Ini memungkinkan pengguna dalam mendeteksi dan menganalisis jejak tumpukan dari program langsung. Itu dapat diluncurkan dari folder /bin dari instalasi Java kami.

Menggunakan alat GUI jconsole kita dapat memeriksa jejak tumpukan setiap utas saat kita menghubungkannya ke proses java yang sedang berjalan. Kemudian, di tab Thread, kita bisa melihat nama semua thread yang sedang berjalan. Untuk mendeteksi kebuntuan, kita dapat mengklik Detect Deadlock di kanan bawah jendela. Jika deadlock terdeteksi maka akan muncul di tab baru jika tidak, No Deadlock Detected akan ditampilkan.

  Apakah Xbox Memiliki Mario Kart?

#6. ThreadMxBean

ThreadMXBean adalah antarmuka untuk pengelolaan sistem utas mesin virtual Java milik paket java.lang.Management. Ini terutama digunakan untuk mendeteksi utas yang telah memasuki situasi kebuntuan dan mendapatkan detail tentangnya.

Kita dapat menggunakan antarmuka ThreadMxBean untuk menangkap dump thread secara terprogram. metode getThreadMXBean() dari ManagementFactory digunakan untuk mendapatkan instance dari antarmuka ThreadMXBean. Ini mengembalikan jumlah utas langsung daemon dan non-daemon. ManagementFactory adalah kelas pabrik untuk mendapatkan kacang terkelola untuk platform Java.

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

Analisis Manual Thread Dumps

Analisis dump thread bisa sangat berguna dalam menentukan masalah dalam proses multithreaded. Masalah seperti deadlock, lock contention, dan penggunaan CPU berlebih oleh thread dump individu dapat diselesaikan dengan memvisualisasikan status thread dump individual.

Throughput maksimum dari aplikasi dapat dicapai dengan memperbaiki status setiap utas setelah menganalisis dump utas.

Misalnya, katakanlah, suatu proses menggunakan banyak CPU, kita dapat mengetahui apakah ada utas yang paling banyak menggunakan CPU. Jika ada utas seperti itu, kami mengonversi nomor LWP-nya ke angka heksadesimal. Kemudian dari thread dump, kita dapat menemukan thread dengan nid sama dengan bilangan heksadesimal yang diperoleh sebelumnya. Dengan menggunakan jejak tumpukan utas, kami dapat menentukan masalahnya. Mari cari tahu id proses dari utas menggunakan perintah di bawah ini.

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

Mari kita lihat potongan thread dump di bawah ini. Untuk mendapatkan thread dump untuk proses 26680, gunakan 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

Sekarang, Mari kita lihat hal-hal apa saja yang dapat kita jelajahi menggunakan thread dump. Jika kami mengamati thread dump, kami dapat melihat banyak konten, yang bisa sangat banyak. Namun, jika kita mengambil satu langkah pada satu waktu, itu bisa cukup sederhana untuk dipahami. Mari kita pahami baris pertama

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

Di atas menampilkan waktu dump dibuat, dan informasi tentang JVM yang digunakan. Selanjutnya, pada akhirnya, kita bisa melihat daftar utas, yang pertama di antaranya adalah utas ReferenceHandler kita.

Menganalisis Utas yang Diblokir

Jika kami menganalisis log dump thread di bawah ini, kami dapat menemukan bahwa thread tersebut telah mendeteksi thread dengan status BLOCKED yang membuat kinerja aplikasi menjadi sangat lambat. Jadi, jika kita dapat menemukan utas yang DIBLOKIR, kita dapat mencoba mengekstrak utas yang terkait dengan kunci yang ingin diperoleh utas tersebut. Analisis jejak tumpukan dari utas yang saat ini memegang kunci dapat membantu memecahkan masalah.

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

Menganalisis Thread yang Deadlock

Aplikasi thread dump lainnya yang sangat umum digunakan adalah deteksi kebuntuan. Deteksi dan solusi kebuntuan bisa jauh lebih mudah jika kita menganalisis dump thread.

Kebuntuan adalah situasi yang melibatkan setidaknya dua utas di mana sumber daya yang diperlukan oleh satu utas untuk melanjutkan eksekusi dikunci oleh utas lainnya dan pada saat yang sama, sumber daya yang diperlukan oleh utas kedua dikunci oleh utas pertama.

Jadi, tidak ada utas yang dapat melanjutkan eksekusi, dan ini menghasilkan situasi kebuntuan dan berakhir dengan aplikasi macet. Jika ada gimbal, maka bagian terakhir dari thread dump akan mencetak informasi mengenai kebuntuan sebagai berikut.

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

Di sini kita dapat melihat informasi kebuntuan dalam format yang dapat dibaca manusia.

  Cara Bergabung dengan Grup di Aplikasi Line Chat

Selain itu, jika kita merangkum semua potongan thread dump di atas bersama-sama, maka informasi di bawah ini akan disebutkan.

  • Penangan referensi adalah nama utas yang dapat dibaca manusia.
  • #2 adalah id unik utas.
  • daemon menunjukkan jika utasnya adalah utas daemon.
  • Prioritas numerik dari utas diberikan oleh prio=10.
  • Status utas saat ini dilambangkan dengan kondisi menunggu.
  • Kemudian kami melihat jejak tumpukan, yang menyertakan informasi penguncian.

Thread Dumps Analyzer

Selain analisis manual, ada banyak alat yang tersedia untuk menganalisis dump thread, baik online maupun offline. Di bawah ini adalah beberapa alat yang terdaftar, yang dapat kami gunakan berdasarkan persyaratan.

Pertama, mari jelajahi alat online.

#1. Benang cepat

Utas Cepat adalah alat analisis thread dump favorit insinyur DevOps untuk memecahkan masalah produksi yang kompleks. Ini adalah Java thread dump analyzer online, Kita dapat mengunggah thread dump sebagai file atau kita dapat langsung menyalin dan menempelkan thread dump.

Bergantung pada ukurannya, itu akan menganalisis tumpukan utas dan menampilkan informasi seperti yang ditunjukkan pada tangkapan layar.

Fitur

  • Memecahkan masalah crash JVM, pelambatan, kebocoran memori, macet, CPU Spikes
  • RCA Instan (jangan menunggu Vendor)
  • Dasbor Intuitif
  • Dukungan REST API
  • Pembelajaran mesin

#2. Spotify Thread Dump Analyzer

Itu Spotify Thread Dump Analyzer dilisensikan di bawah versi 2.0 dari lisensi Apache. Ini adalah alat online dan menerima dump thread sebagai file atau kita dapat langsung menyalin dan menempelkan dump thread. Bergantung pada ukurannya, itu akan menganalisis tumpukan utas dan menampilkan informasi seperti yang ditunjukkan pada tangkapan layar.

#3. Ulasan Jstack

Jstack.ulasan menganalisis dump thread java dari dalam browser. Halaman ini hanya untuk sisi klien.

#4. Situs 24×7

Ini alat adalah prasyarat untuk mendeteksi utas yang salah yang menurunkan kinerja Java Virtual Machine (JVM). Masalah seperti deadlock, lock contention, dan penggunaan CPU berlebih oleh thread dump individu dapat diselesaikan dengan memvisualisasikan status thread dump individual.

Throughput maksimum dari aplikasi dapat dicapai dengan memperbaiki status setiap utas yang disediakan oleh alat tersebut.

Sekarang, mari jelajahi alat luring.

Dalam hal pembuatan profil, hanya alat terbaik yang cukup baik.

#1. JProfiler

JProfiler adalah salah satu penganalisa dump thread paling populer di antara pengembang Java. UI intuitif JProfiler membantu Anda mengatasi hambatan kinerja, menemukan kebocoran memori, dan memahami masalah threading.

JProfiler mendukung pembuatan profil pada platform berikut:

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

Di bawah ini adalah beberapa fitur yang menjadikan JProfiler sebagai pilihan utama untuk membuat profil aplikasi kita di JVM.

Fitur

  • Mendukung pembuatan profil basis data untuk JDBC, JPA, dan NoSQL
  • Dukungan untuk edisi perusahaan Java juga tersedia
  • Menyajikan informasi tingkat tinggi tentang panggilan RMI
  • Analisis Stellar tentang kebocoran memori
  • Kemampuan QA yang luas
  • Profiler utas terintegrasi terintegrasi erat dengan tampilan profil CPU.
  • Dukungan untuk platform, IDE, dan server aplikasi.

#2. TMDA IBM

IBM Thread dan Monitor Dump Analyzer untuk Java (TMDA) adalah alat yang memungkinkan identifikasi hang, deadlock, perebutan sumber daya, dan kemacetan di thread dump Java. Ini adalah produk IBM tetapi alat TMDA disediakan tanpa jaminan atau dukungan apa pun; namun, mereka mencoba memperbaiki dan menyempurnakan alat tersebut dari waktu ke waktu.

#3. ManageEngine

ManageEngine manajer aplikasi dapat membantu memantau memori JVM Heap dan Non-Heap. Kami bahkan dapat mengonfigurasi ambang dan diberi tahu melalui email, SMS, dll, dan memastikan aplikasi Java disetel dengan baik.

#4. YourKit

YourKit terdiri dari produk-produk di bawah ini yang disebut sebagai Kit.

  • Java Profiler – Low overhead profiler berfitur lengkap untuk platform Java EE dan Java SE.
  • YouMonitor – Pemantauan kinerja dan pembuatan profil Jenkins, TeamCity, Gradle, Maven, Ant, JUnit, dan TestNG.
  • .NET Profiler – Profiler kinerja dan memori yang mudah digunakan untuk .NET framework.

Kesimpulan

Sekarang Anda tahu, bagaimana thread dump berguna dalam memahami dan mendiagnosis masalah pada aplikasi multithreaded. Dengan tepat pengetahuanmengenai thread dump – strukturnya, informasi yang terkandung di dalamnya, dan seterusnya – kita dapat memanfaatkannya untuk mengidentifikasi penyebab masalah dengan cepat.