Bagaimana menganalisis java thread dump?

100

Saya mencoba memahami lebih banyak tentang java, terutama tentang manajemen memori dan utas. Untuk alasan ini saya baru-baru ini menemukan minat untuk melihat pembuangan benang.

Berikut adalah beberapa baris yang diambil dari aplikasi web menggunakan VisualVM, alat bawaan untuk java:

"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
    - None

"Reference Handler" daemon prio=10 tid=0x02b3b800 nid=0x494 in Object.wait() [0x02cbf000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27ef0310> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x27ef0310> (a java.lang.ref.Reference$Lock)

Pertama saya punya pertanyaan tentang beberapa nama variabel:

  • apa artinya tid dan nid?
  • Berapa angka dalam tanda kurung setelah Object.wait?

Kemudian untuk pelacakan tumpukan itu sendiri:

  • apa artinya menunggu <.....> (a java.lang ....) dan berapa angka di <..>
  • apa artinya terkunci <.....> (a java.lang ....) pertanyaan yang sama, ada apa di <..>

Saya pikir kata terkunci bagaimanapun juga terkait dengan kondisi menunggu, namun, saya salah. Sebenarnya, saya bertanya-tanya mengapa terkunci diulang tiga kali, tetapi utas dalam keadaan dapat dijalankan seperti yang terlihat di dump yang sama:

"Thread-0" prio=6 tid=0x02ee3800 nid=0xc1c runnable [0x03eaf000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:199)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
    - locked <0x23963378> (a java.io.BufferedInputStream)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    - locked <0x23968450> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    - locked <0x23968450> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:145)

Kemudian yang terakhir dari semuanya, ini yang terburuk dari mereka:

"CompilerThread0" daemon prio=10 tid=0x02b81000 nid=0x698 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

Utas ini dalam keadaan dapat dijalankan, tetapi menunggu dengan syarat. Kondisi apa dan apa itu 0x00000?

Mengapa pelacakan tumpukan sangat pendek tanpa bukti kelas utas?

Jika Anda bisa menjawab semua pertanyaan saya, saya akan sangat berterima kasih.

Terima kasih

Leonardo
sumber

Jawaban:

113

TID adalah id id dan NID adalah: Native thread ID. ID ini sangat bergantung pada platform. Ini adalah NID di jstack thread dumps. Di Windows, ini hanyalah ID utas tingkat OS dalam suatu proses. Di Linux dan Solaris, ini adalah PID dari utas (yang pada gilirannya merupakan proses yang ringan). Di Mac OS X, ini disebut sebagai nilai pthread_t asli.

Buka tautan ini: ID utas tingkat Java : untuk definisi dan penjelasan lebih lanjut tentang kedua istilah ini.

Di situs IBM saya menemukan tautan ini: Bagaimana menafsirkan thread dump . yang membahas ini secara lebih rinci:

Ini menjelaskan apa artinya menunggu itu: Kunci mencegah lebih dari satu entitas mengakses sumber daya bersama. Setiap objek di Java ™ memiliki kunci terkait (diperoleh dengan menggunakan blok atau metode tersinkronisasi). Dalam kasus JVM, utas bersaing untuk berbagai sumber daya di JVM dan mengunci objek Java.

Kemudian menjelaskan monitor sebagai jenis mekanisme penguncian khusus yang digunakan di JVM untuk memungkinkan sinkronisasi yang fleksibel antar utas. Untuk tujuan bagian ini, baca istilah monitor dan kunci secara bergantian.

Kemudian melangkah lebih jauh:

Untuk menghindari monitor pada setiap objek, JVM biasanya menggunakan sebuah flag dalam class atau method block untuk menunjukkan bahwa item tersebut terkunci. Sebagian besar waktu, sepotong kode akan mentransmisikan beberapa bagian terkunci tanpa perselisihan. Oleh karena itu, bendera penjaga sudah cukup untuk melindungi kode ini. Ini disebut monitor datar. Namun, jika utas lain ingin mengakses beberapa kode yang dikunci, pertengkaran asli telah terjadi. JVM sekarang harus membuat (atau memompa) objek monitor untuk menahan utas kedua dan mengatur mekanisme pensinyalan untuk mengoordinasikan akses ke bagian kode. Monitor ini sekarang disebut monitor yang digelembungkan.

Berikut adalah penjelasan yang lebih mendalam tentang apa yang Anda lihat di baris dari thread dump. Utas Java diimplementasikan oleh utas asli sistem operasi. Setiap utas diwakili oleh garis yang dicetak tebal seperti:

"Thread-1" (TID: 0x9017A0, sys_thread_t: 0x23EAC8, state: R, native ID: 0x6E4) prio = 5

* 6 item berikut menjelaskan hal ini karena saya telah mencocokkannya dari contoh, nilai dalam tanda kurung []:

  1. nama [ Thread-1 ],
  2. pengenal [ 0x9017A0 ],
  3. Alamat struktur data JVM [ 0x23EAC8 ],
  4. keadaan saat ini [ R ],
  5. pengenal utas asli [ 0x6E4 ],
  6. dan prioritas [ 5 ].

"Tunggu" tampaknya adalah utas daemon yang terkait dengan jvm itu sendiri dan bukan utas aplikasi perse. Ketika Anda mendapatkan "di Object.wait ()", itu berarti untaian daemon, "finalizer" di sini, sedang menunggu pemberitahuan tentang kunci pada objek, dalam hal ini menunjukkan kepada Anda pemberitahuan apa yang ditunggunya: "- menunggu <0x27ef0288> (a java.lang.ref.ReferenceQueue $ Lock) "

Definisi ReferenceQueue adalah: Antrean referensi, yang objek referensi terdaftar ditambahkan oleh pengumpul sampah setelah perubahan jangkauan yang sesuai terdeteksi.

Rangkaian finalizer berjalan sehingga pengumpulan sampah beroperasi untuk membersihkan sumber daya yang terkait dengan suatu objek. Jika saya melihatnya dengan benar, finalizer tidak bisa mendapatkan kunci ke objek ini: java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118) karena objek java menjalankan metode, jadi utas finalizer adalah terkunci sampai objek itu selesai dengan tugasnya saat ini.

Selain itu, finalizer tidak hanya mencari untuk mendapatkan kembali memori, itu lebih terlibat daripada membersihkan sumber daya. Saya perlu melakukan lebih banyak studi tentang itu, tetapi jika Anda memiliki file yang terbuka, soket, dll ... terkait dengan metode objek, maka finalizer akan bekerja untuk membebaskan item itu juga.

Berapa angka dalam tanda kurung setelah Object.wait di thread dump?

Ini adalah penunjuk dalam memori ke utas. Berikut penjelasan yang lebih detail:

C.4.1 Informasi Thread

Bagian pertama dari bagian utas menunjukkan utas yang memicu kesalahan fatal, sebagai berikut:

Current thread (0x0805ac88):  JavaThread "main" [_thread_in_native, id=21139]
                    |             |         |            |          +-- ID
                    |             |         |            +------------- state
                    |             |         +-------------------------- name
                    |             +------------------------------------ type
                    +-------------------------------------------------- pointer

Penunjuk utas adalah penunjuk ke struktur utas internal Java VM. Ini umumnya tidak menarik kecuali Anda men-debug VM Java langsung atau file inti.

Deskripsi terakhir ini berasal dari: Panduan Mengatasi Masalah untuk Java SE 6 dengan HotSpot VM

Berikut ini beberapa tautan lagi di thread dump:

James Drinkard
sumber
11

Lebih lanjut untuk jawaban luar biasa @James Drinkard:

Perhatikan bahwa, bergantung pada implementasi yang mendasarinya, java.lang.Thread.State dari utas yang diblokir dalam metode asli dapat dilaporkan sebagai RUNNABLE, di manaA thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

Ternyata deskripsi ini juga mencakup pemblokiran dalam panggilan OS seperti polling atau operasi baca - mungkin karena tidak ada jaminan bahwa JVM dapat mengetahui saat panggilan metode native diblokir di tingkat OS.

Banyak diskusi tentang dump thread JVM yang telah saya lihat mengabaikan kemungkinan ini sepenuhnya, atau dengan senang hati membacanya tanpa mempertimbangkan implikasinya - paling tidak adalah bahwa alat pemantauan dapat secara membingungkan melaporkan bahwa beberapa thread seperti itu 'berjalan', dan lebih jauh lagi itu semuanya berjalan pada 100%.

Jeremy
sumber