Java iş parçacığı dökümü nasıl analiz edilir?


100

Java hakkında, özellikle bellek yönetimi ve iş parçacıkları hakkında daha fazla şey anlamaya çalışıyorum. Bu nedenle, son zamanlarda iş parçacığı dökümlerine bakmaya ilgi duydum.

Java için yerleşik bir araç olan VisualVM kullanılarak bir web uygulamasından alınan birkaç satır:

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

Öncelikle bazı değişken isimleriyle ilgili sorularım var:

  • tid ve nid ne anlama geliyor?
  • Object.wait'den sonraki kare parantez içindeki rakam nedir?

Ardından yığın izinin kendisi için:

  • <.....> 'da (java.lang ....) beklemek ne anlama geliyor ve <..> içindeki numara kaç
  • kilitli ne demek <.....> (java.lang ....) aynı soru, <..> içinde ne var

Kilitli kelimesinin bir şekilde bekleme durumuyla ilişkili olduğunu düşündüm, ancak yanılmışım. Aslında, kilitlemenin neden üç kez tekrarlandığını merak ediyorum, ancak iş parçacığı aynı dökümde görüldüğü gibi çalıştırılabilir durumda:

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

Son olarak, bu onların en kötüsüydü:

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

Bu iş parçacığı çalıştırılabilir durumda, ancak koşulda bekliyor. 0x00000 koşulu ve nedir?

Yığın izleme, iş parçacığı sınıfının herhangi bir kanıtı olmadan neden bu kadar kısa?

Tüm sorularıma cevap verirseniz çok minnettar olurum.

Teşekkürler

Yanıtlar:


113

TID thead id ve NID: Yerel iş parçacığı kimliği. Bu kimlik, büyük ölçüde platforma bağlıdır. Jstack iş parçacığı dökümlerindeki NID'dir. Windows'ta, bir işlem içindeki işletim sistemi düzeyindeki iş parçacığı kimliğidir. Linux ve Solaris'te, iş parçacığının PID'sidir (bu da hafif bir işlemdir). Mac OS X'te, yerel pthread_t değeri olduğu söylenir.

Bu bağlantıya gidin: Java düzeyinde iş parçacığı kimliği : bu iki terimin bir tanımı ve daha fazla açıklaması için.

IBM'in sitesinde şu bağlantıyı buldum: Bir iş parçacığı dökümü nasıl yorumlanır . bunu daha ayrıntılı olarak kapsar:

Beklemenin ne anlama geldiğini açıklıyor: Kilit, birden fazla varlığın paylaşılan bir kaynağa erişmesini engeller. Java ™ 'daki her nesnenin ilişkili bir kilidi vardır (senkronize edilmiş bir blok veya yöntem kullanılarak kazanılır). JVM durumunda, iş parçacıkları JVM'deki çeşitli kaynaklar için rekabet eder ve Java nesnelerini kilitler.

Daha sonra monitörü, dişler arasında esnek senkronizasyon sağlamak için JVM'de kullanılan özel bir tür kilitleme mekanizması olarak tanımlar. Bu bölümün amacı için, birbirlerinin yerine izleme ve kilitleme terimlerini okuyun.

Sonra daha da ileri gider:

Her nesnede bir monitör olmasını önlemek için, JVM genellikle öğenin kilitli olduğunu belirtmek için bir sınıf veya yöntem bloğunda bir bayrak kullanır. Çoğu zaman, bir kod parçası kilitli bir bölümü çekişmeden aktarır. Bu nedenle, koruyucu bayrak bu kod parçasını korumak için yeterlidir. Buna düz monitör denir. Bununla birlikte, başka bir iş parçacığı kilitli olan bir koda erişmek isterse, gerçek bir çekişme oluşmuştur. JVM şimdi ikinci iş parçacığını tutmak için monitör nesnesini oluşturmalı (veya şişirmelidir) ve kod bölümüne erişimi koordine etmek için bir sinyal verme mekanizması düzenlemelidir. Bu monitör artık şişirilmiş monitör olarak adlandırılıyor.

İplik dökümünden gelen satırlarda gördüklerinizin daha derinlemesine bir açıklaması. Java iş parçacığı, işletim sisteminin yerel iş parçacığı tarafından uygulanır. Her iş parçacığı aşağıdaki gibi kalın bir satırla temsil edilir:

"Konu-1" (TID: 0x9017A0, sys_thread_t: 0x23EAC8, durum: R, yerel kimlik: 0x6E4) prio = 5

* Aşağıdaki 6 öğe, bunları örnekten eşleştirdiğim için açıklıyor, parantez içindeki değerler []:

  1. isim [ Konu-1 ],
  2. tanımlayıcı [ 0x9017A0 ],
  3. JVM veri yapısı adresi [ 0x23EAC8 ],
  4. mevcut durum [ R ],
  5. yerel iş parçacığı tanımlayıcısı [ 0x6E4 ],
  6. ve öncelik [ 5 ].

"Bekle", uygulama iş parçacığı perse değil, jvm'nin kendisiyle ilişkili bir arka plan programı iş parçacığı gibi görünüyor. Bir "in Object.wait ()" aldığınızda, buradaki arka plan iş parçacığı, "finalizer", bir nesnedeki kilitle ilgili bir bildirim beklediği anlamına gelir, bu durumda size beklediği bildirimi gösterir: "- <0x27ef0288> bekleniyor (bir java.lang.ref.ReferenceQueue $ Lock) "

ReferenceQueue'nun tanımı şudur: Kayıtlı referans nesnelerinin uygun erişilebilirlik değişiklikleri tespit edildikten sonra çöp toplayıcı tarafından eklendiği referans kuyrukları.

Sonlandırıcı iş parçacığı, bir nesneyle ilişkili kaynakları temizlemek için çöp toplama işleminin çalıştığı şekilde çalışır. Doğru bir şekilde görüyorsam, sonlandırıcı bu nesneye kilidi alamaz: java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118) çünkü java nesnesi bir yöntem çalıştırıyor, bu nedenle sonlandırıcı iş parçacığı o nesne mevcut göreviyle tamamlanana kadar kilitlenir.

Ayrıca, sonlandırıcı sadece hafızayı geri kazanmak değil, kaynakları temizlemek için bundan daha fazlasını gerektirir. Bunun üzerinde daha fazla çalışma yapmam gerekiyor, ancak nesnelerin yöntemleriyle ilgili açık dosyalarınız, soketleriniz vb. Varsa, sonlandırıcı da bu öğeleri serbest bırakmak için çalışacaktır.

İplik dökümünde Object.wait'den sonra kare parantez içindeki rakam nedir?

İpliğin hafızasında bir göstericidir. İşte daha ayrıntılı bir açıklama:

C.4.1 Konu Bilgileri

İş parçacığı bölümünün ilk kısmı, aşağıdaki gibi ölümcül hatayı tetikleyen iş parçacığını gösterir:

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

İş parçacığı işaretçisi, Java VM dahili iş parçacığı yapısının göstericisidir. Canlı bir Java sanal makinesinde veya çekirdek dosyasında hata ayıklamadığınız sürece genellikle ilgilenilmez.

Bu son açıklama şuradan geldi: HotSpot VM ile Java SE 6 için Sorun Giderme Kılavuzu

İşte ileti dizisi dökümleriyle ilgili birkaç bağlantı daha:


11

@ James Drinkard'ın mükemmel cevabına ek olarak:

Temel uygulamaya bağlı olarak, yerel bir yöntemde engellenen bir iş parçacığının java.lang.Thread.State öğesinin RUNNABLE,A 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.

Bu açıklamanın aynı zamanda bir anket veya okuma işlemi gibi bir işletim sistemi çağrısında engellenmeyi de kapsadığı ortaya çıkmıştır - muhtemelen JVM'nin işletim sistemi düzeyinde yerel bir yöntem çağrısının ne zaman engellendiğini bilebileceğine dair hiçbir garanti yoktur.

Gördüğüm JVM iş parçacığı dökümü tartışmalarının çoğu, bu olasılığı tamamen görmezden geliyor ya da sonuçları dikkate almadan pervasızca gözden geçiriyor - en önemlisi, izleme araçlarının bu tür birkaç iş parçacığının 'çalıştığını' kafa karıştırıcı bir şekilde rapor edebilmesi ve dahası hepsi% 100 çalışıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.