Java、特にメモリ管理とスレッドについてもっと理解しようとしています。このため、最近、スレッドダンプを調べることに興味を持ちました。
Java用の組み込みツールであるVisualVMを使用した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)
最初に、いくつかの変数名について質問があります。
次に、スタックトレース自体について:
ロックされたWordは何らかの形で待機状態に関係していると思いましたが、間違っていました。実際、なぜロックが3回繰り返されるのか疑問に思っていますが、同じダンプで見られるように、スレッドは実行可能な状態にあります。
"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とはどのような状態ですか?
スレッドクラスの証拠なしでスタックトレースが非常に短いのはなぜですか?
あなたが私のすべての質問に答えることができれば、私は非常に感謝するでしょう。
ありがとう
TIDはthead idで、NIDは:ネイティブスレッドIDです。このIDは、プラットフォームに大きく依存しています。 jstackスレッドダンプのNIDです。 Windowsでは、単にプロセス内のOSレベルのスレッドIDです。 LinuxおよびSolarisでは、スレッドのPIDです(これは軽量プロセスです)。 Mac OS Xでは、ネイティブのpthread_t値と言われています。
次のリンクに移動します。 JavaレベルのスレッドID :これら2つの用語の定義と詳細については、.
IBMのサイトでこのリンクを見つけました: スレッドダンプの解釈方法 。これについて詳しく説明します。
待機の意味を説明しています。ロックは、複数のエンティティが共有リソースにアクセスするのを防ぎます。 Java™の各オブジェクトには、関連付けられたロックがあります(同期ブロックまたはメソッドを使用して取得)。 JVMの場合、スレッドはJVMのさまざまなリソースを奪い合い、Javaオブジェクトをロックします。
次に、モニターを、スレッド間の柔軟な同期を可能にするためにJVMで使用される特別な種類のロックメカニズムとして説明します。このセクションでは、モニターとロックという用語を同じ意味で読みます。
その後、さらに進みます。
すべてのオブジェクトのモニターを回避するために、JVMは通常、クラスまたはメソッドブロックでフラグを使用して、アイテムがロックされていることを示します。ほとんどの場合、コードは競合することなくロックされたセクションを通過します。したがって、ガーディアンフラグはこのコードを保護するのに十分です。これはフラットモニターと呼ばれます。ただし、別のスレッドがロックされているコードにアクセスする必要がある場合は、真の競合が発生しています。 JVMは、2番目のスレッドを保持し、コードセクションへのアクセスを調整するシグナリングメカニズムを準備するために、モニターオブジェクトを作成(または膨張)する必要があります。このモニターは現在、水増しモニターと呼ばれています。
スレッドダンプの行に表示されている内容について、さらに詳しく説明します。 Javaスレッドは、オペレーティングシステムのネイティブスレッドによって実装されます。各スレッドは、次のような太字の行で表されます。
"Thread-1"(TID:0x9017A0、sys_thread_t:0x23EAC8、state:R、native ID:0x6E4)prio = 5
*次の6つの項目は、例からそれらを一致させたため、これを説明しています。値は角かっこ[]にあります:
「待機」は、アプリケーションスレッド自体ではなく、jvm自体に関連付けられたデーモンスレッドのようです。 「in Object.wait()」を取得すると、デーモンスレッド「finalizer」がオブジェクトのロックに関する通知を待機していることを意味します。この場合、待機している通知が表示されます。 <0x27ef0288>(Java.lang.ref.ReferenceQueue $ Lock)で待機しています」
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
スレッドダンプに関するリンクをいくつか次に示します。
@James 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.
おそらく、JVMがネイティブメソッド呼び出しがOSレベルでブロックされたことを知ることができるという保証がないため、この説明には、ポーリングや読み取り操作などのOS呼び出しでブロックされることも含まれます。
私が見たJVMスレッドダンプの多くの議論は、この可能性を完全に無視するか、意味を考慮せずに軽やかに読みます-特に、監視ツールはそのようなスレッドがいくつか実行されていると混乱して報告する可能性があり、さらにそれらはすべて100%で実行されています。