2011-09-29 192 views
78

我想了解更多關於java的知識,特別是關於內存管理和線程。 因爲這個原因,我最近發現有興趣看看線程轉儲。如何分析java線程轉儲?

下面是使用VisualVM的,一個Java的內置工具從一個Web應用程序所採取的幾行:

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

首先我有一些變量名的問題:

  • 什麼呢TID和nid是什麼意思?
  • Object.wait之後的圓括號中的數字是什麼?

然後堆棧跟蹤本身:

  • 這是什麼意思等待< .....>(一java.lang中....),什麼是在數< ..>
  • 這是什麼意思鎖定< .....>(一java.lang中....)同樣的問題,什麼是在< ..>

我認爲鎖定這個詞在某種程度上與等待條件有關,但是,我錯了。其實,我很奇怪,爲什麼鎖定重複三次,但線程處於可運行狀態,在同一個轉儲看出:

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

然後最後的是,這是最嚴重的:

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

此線程處於可運行狀態,但它正在等待條件。什麼樣的條件和什麼是0x00000?

爲什麼堆棧跟蹤太短而沒有任何線程類的證據?

如果你能回答我所有的問題,我將非常感激。

謝謝

回答

100

該TID是thead id和NID是:本機線程ID。該ID與平臺高度相關。這是jstack線程轉儲中的NID。在Windows上,它只是一個進程中的操作系統級別的線程ID。在Linux和Solaris上,它是線程的PID(這又是一個輕量級進程)。在Mac OS X上,它被稱爲本地pthread_t值。

轉到此鏈接:Java-level thread ID:有關這兩個術語的定義和進一步解釋。

在IBM的網站上,我找到了這個鏈接:How to interpret a thread dump。詳細說明如下:

它解釋了等待意味着什麼: 鎖可以防止多個實體訪問共享資源。 Java™中的每個對象都有一個關聯的鎖(通過使用同步塊或方法獲得)。在JVM的情況下,線程競爭JVM中的各種資源並鎖定Java對象。

然後它將監視器描述爲JVM中使用的特殊類型的鎖定機制,以允許線程間的靈活同步。爲了達到本節的目的,請閱讀術語「監視器」並互換鎖定。

然後,它更進一步:

爲了避免每個對象上的顯示器,JVM通常使用的標誌在一個類或方法的塊,以指示該項目已被鎖定。大多數情況下,一段代碼將通過一些鎖定部分而不會引起爭用。因此,監護人標誌足以保護這段代碼。這被稱爲平板顯示器。但是,如果另一個線程想要訪問某些被鎖定的代碼,就會發生真正的爭用。 JVM現在必須創建(或擴充)監視對象來保存第二個線程,並安排信號機制來協調對代碼段的訪問。這臺顯示器現在稱爲充氣顯示器。

下面是關於線程轉儲中您看到的內容的更深入的說明。 Java線程由操作系統的本地線程實現。每個線程由一條線表示粗體如:

「線程1」(TID:0x9017A0,sys_thread_t:0x23EAC8,狀態:R,天然ID:0x6E4)PRIO = 5

*的以下6項說明該正如我已經從例如它們匹配,在方括號[]值:

  1. 名稱[TID:0x9017A0],
  2. 標識符[sys_thread_t],
  3. JVM數據結構地址[0x23EAC8],
  4. 當前狀態[狀態:R t],
  5. 本地線程標識符[0x6E4],
  6. 和優先級[PRIO = 5] 。

「等待」似乎是與jvm本身相關的守護程序線程,而不是應用程序線程持續。當你得到一個「in Object.wait()」時,這意味着這裏的守護進程線程「終結器」正在等待一個關於對象鎖定的通知,在這種情況下它會告訴你它正在等待什麼通知: 「 - 等待< 0x27ef0288>(一個java.lang.ref.ReferenceQueue $鎖定)」的的ReferenceQueue的

定義是: 引用隊列中,向其中註冊的引用對象被垃圾收集適當的可到達性更改後所附被檢測到。

終結器線程運行,所以垃圾收集操作清理與對象關聯的資源。如果我正確地看到它,終結器無法獲得對該對象的鎖定:java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118),因爲java對象正在運行一個方法,所以終結器線程是直到該對象完成當前任務。

此外,終結器不只是回收內存,它比清理資源涉及更多。我需要對它進行更多的研究,但是如果你有文件打開,套接字等等與對象方法有關,那麼終結器也將把這些項目釋放。

線程轉儲中的Object.wait之後的圓括號中的數字是什麼?

它是內存中的線程的指針。下面是一個更詳細的描述:

C.4.1線程信息

螺紋部分的第一部分示出了引起致命錯誤線程,如下所示:

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

線程指針是指向Java VM內部線程結構的指針。除非您正在調試活動的Java VM或核心文件,否則它通常不感興趣。

最後這說明來自:Troubleshooting Guide for Java SE 6 with HotSpot VM

這裏有螺紋幾個環節轉儲:

6

繼@詹姆斯Drinkard的出色答卷:

需要注意的是,依賴於底層實現,被阻止在本地方法的線程的java.lang.Thread.State可能被報告爲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.

事實證明,這個描述還包含在諸如輪詢或讀取操作的OS調用中被阻塞 - 可能是因爲不能保證JVM能夠知道本機方法調用何時在操作系統級被阻塞。

很多關於JVM線程轉儲的討論我都已經完全忽略了這種可能性,或者在不考慮其含義的情況下輕鬆地瀏覽它 - 其中最重要的是監控工具可能會令人困惑地報告幾個這樣的線程正在「運行」 ,而且他們都在100%運行。