Javaコマンド学習シリーズ(2つ)-Jstack

Javaコマンド学習シリーズ(2つ)-Jstack

トピックに含まれて

7 、Linuxのコマンド

jstackは、java仮想マシンに付属するスタックトレースツールです。

特徴


jstackは、現時点でjava仮想マシンのスレッドスナップショットを生成するために使用されます。スレッドスナップショットは、現在のjava仮想マシンの各スレッドによって実行されているメソッドスタックのコレクションです。スレッドスナップショットを生成する主な目的は、スレッド間のデッドロック、エンドレスループ、外部リソース要求による長期間など、スレッドの長い一時停止の原因を特定することです。待つ時間。スレッドが一時停止すると、jstackを介して各スレッドの呼び出しスタックを表示でき、応答しないスレッドがバックグラウンドで何を行っているか、またはどのリソースが待機しているかを知ることができます。javaプログラムがクラッシュしてコアファイルが生成された場合、jstackツールを使用してコアファイルのjavaスタックとネイティブスタックの情報を取得できるため、javaプログラムがクラッシュした方法と問題が発生した場所を簡単に知ることができます。さらに、jstackツールを実行中のjavaプログラムにアタッチすることもでき、その時点で実行中のjavaプログラムのjavaスタックとネイティブスタックの情報を確認できます。現在実行中のjavaプログラムがハング状態を示している場合、jstackは非常に便利です。

So、jstackコマンドは、主にJavaスレッドの呼び出しスタックを表示するために使用され、スレッドの問題(デッドロックなど)を分析するために使用できます。

スレッドの状態

jstackコマンドを使用してスレッドの状況を分析する場合は、最初にスレッドの状態を知る必要があります。次の状態は、jstackコマンドを使用してスレッドスタック情報を表示するときに表示される可能性のあるスレッドのいくつかの状態です。

NEW、アクティブ化されていません。ダンプには表示されません。

RUNNABLE、仮想マシンで実行されます。

ブロックされ、ブロックされ、モニターがロックされるのを待っています。

WATING、別のスレッドが特定の操作を実行するのを無期限に待機します。

TIMED_WATING、別のスレッドの特定の操作を待機する時間制限。

終了しました、取り下げられました。

モニター

マルチスレッドJAVAプログラムでは、スレッド間の同期を実現するために、モニターについて話す必要があります。モニターは、Javaのスレッド間の相互排除と協調を実現するために使用される主要なメソッドであり、オブジェクトまたはクラスのロックと見なすことができます。すべてのオブジェクトには、モニターが1つだけあります。次の図は、スレッドとモニターの関係、およびスレッドの状態遷移図を示しています。
Javaコマンド学習シリーズ(2つ)-Jstack

Entrt Set:スレッドが同期された要求を通じてオブジェクトのロックを取得することを示します。オブジェクトがロックされていない場合は、所有者を入力します。それ以外の場合は、入力ゾーンで待機します。オブジェクトロックが他のスレッドによって解放されると、すぐに競争に参加します。

所有者(所有者):スレッドがオブジェクトロックを正常に競合したことを示します。

待機領域(待機セット):スレッドがオブジェクトの待機メソッドを介してオブジェクトのロックを解放し、待機領域でウェイクアップされるのを待機することを示します。

図からわかるように、モニターは特定の時間に1つのスレッドのみが所有できます。このスレッドは「アクティブスレッド」であり、他のスレッドは「待機スレッド」であり、それぞれ「エントリセット」と「エントリセット」と「待機スレッド」の2つのキューにあります。 「ウェイトセット」でお待ちください。「エントリセット」で待機しているスレッドの状態は「モニタエントリを待機中」であり、「待機セット」で待機しているスレッドの状態は「Object.wait()内」です。まず、「エントリセット」のスレッドを確認します。同期されたクリティカルセクションによって保護されたコードセグメントを呼び出します。スレッドがクリティカルセクションに入るために適用されると、スレッドは「エントリセット」キューに入ります。対応するコードは次のようなものです。


synchronized(obj) {
.........

}

装飾を呼び出す

メソッドが呼び出されたときのスレッドの非常に重要な操作を示します。スレッドダンプ分析の重要な情報。上記のメソッド呼び出しを装飾します。

ロックされた<アドレス>目標:モニターの所有者は、同期を使用してオブジェクトロックを正常に申請します。

ロックを待機中<アドレス>目標:同期を使用してオブジェクトロックの申請に失敗し、着信領域で待機します。

<address>で待機目標:同期を使用してオブジェクトロックを正常に申請した後、ロックを解除して待機領域で待機します。

<address>ターゲットを待つための駐車

ロックされています

at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement

同期キーワードを使用して、オブジェクトのロックを正常に取得し、モニターの所有者になり、重要な領域で操作しました。オブジェクトロックはスレッドリエントリーです。

ロックを待っています

at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165)
- waiting to lock <0x0000000097ba9aa8> (a CacheHolder)
at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder
at com.jiuqi.dna.core.impl.ContextImpl.find
at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo

同期キーワードを使用すると、オブジェクトのロックは取得されず、スレッドはモニターの入力領域で待機します。コールスタックの一番上に表示され、スレッドのステータスはブロックされています。

待っている

at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run

同期キーワードを使用して、オブジェクトのロックを正常に取得した後、waitメソッドを呼び出し、待機するオブジェクトの待機領域に入ります。コールスタックの最上位では、スレッドのステータスはWAITINGまたはTIMED_WATINGです。

待つ駐車場

パークは基本的なスレッドブロックプリミティブであり、モニターを介してオブジェクトをブロックしません。コンカレントパッケージで表示される新しいメカニズムは、非同期システムとは異なります。

スレッドアクション

スレッド状態の理由

runnable:ステータスは通常RUNNABLEです。

Object.wait()内:待機領域で待機中のステータスは、WAITINGまたはTIMED_WAITINGです。

モニターの入力を待機中:ゾーンへの入力を待機中、状態はBLOCKEDです。

条件付きで待機中:待機エリアで待機中、駐車中。

sleeping:眠っているスレッドはThread.sleep()を呼び出しました。

条件待ちこの状態は、スレッドが特定の条件の発生を待機しているときに表示されます。特定の理由は、stacktraceと組み合わせて分析できます。最も一般的な状況は、スレッドがスリープ状態にあり、目覚めるのを待っていることです。一般的な状況は、ネットワークIOを待機することです。javaがnioを導入する前は、ネットワーク接続ごとに、ネットワークの読み取りおよび書き込み操作を処理する対応するスレッドがありました。読み取りおよび書き込み可能なデータがない場合でも、スレッドは読み取りおよび書き込み操作でブロックされます。一方、これはリソースの浪費を引き起こし、オペレーティングシステムのスレッドスケジューリングに圧力をかける可能性があります。NewIOには新しいメカニズムが採用され、作成されたサーバープログラムのパフォーマンスとスケーラビリティが向上しています。ネットワークの読み取りと書き込みを待っている場合、これはネットワークのボトルネックの兆候である可能性があります。ネットワークが混雑しているため、スレッドを実行できません。1つの状況は、ネットワークが非常にビジーで、ほとんどすべての帯域幅を消費し、ネットワークの読み取りと書き込みを待機している大量のデータがまだあることです。もう1つの状況は、ネットワークがアイドル状態であるが、ルーティングの問題のために、パケットが正常に到着できないことです。したがって、システムのパフォーマンス監視ツールを組み合わせて、システム帯域幅の制限を明らかに超えている場合は、単位時間あたりの送信パケット数のnetstat統計など、包括的な分析を行う必要があります。システム状態のCPU時間が、ユーザーモードでのCPU時間の割合は比較的高いです。プログラムがSolaris10プラットフォームで実行されている場合、読み取り/書き込みシステム呼び出しの数を観察するか、実行時間がはるかに進んでいる場合は、dtraceツールを使用してシステム呼び出しの状況を確認できます。これらはすべてネットワークを指しています。帯域幅の制限によって引き起こされるネットワークのボトルネック。(http://www.blogjava.net/jzone/articles/303979.htmlから)

スレッドダンプの分析


原則として

コード読み取り推論を組み合わせます。スレッドダンプとソースコードの相互派生と検証が必要です。

バグの根本的な原因は、多くの場合、呼び出しスタックに直接反映されないため、スレッドの現在の呼び出しの前に、すべての呼び出しに特別な注意を払う必要があります。

出発地点

エリアで待っています

"d&a-3588" daemon waiting for monitor entry [0x000000006e5d5000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.dna.bap.authority.service.UserService$LoginHandler.handle()
- waiting to lock <0x0000000602f38e90> (a java.lang.Object)
at com.jiuqi.dna.bap.authority.service.UserService$LoginHandler.handle()

スレッド状態がブロックされ、スレッドアクションがモニターエントリを待機し、ロックを待機している呼び出し変更が常に一緒に表示されます。コードレベルですでに競合する呼び出しがあることを示します。問題のあるコードが存在する必要があり、その発生を最小限に抑える必要があります。

同期ブロックブロッキング

1つのスレッドがオブジェクトをロックし、他の多数のスレッドがオブジェクトを待機します。


"blocker" runnable
java.lang.Thread.State: RUNNABLE
at com.jiuqi.hcl.javadump.Blocker$1.run(Blocker.java:23)
- locked <0x00000000eb8eff68> (a java.lang.Object)
"blockee-11" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)
"blockee-86" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)

継続的に実行されているIOIO操作は、RUNNABLE状態でブロックできます。例:データベースのデッドロック、ネットワークの読み取りと書き込み。IOスレッドの実際の状態の分析に特に注意してください。一般的に、RUNNABLEでキャッチされたIO呼び出しはすべて問題があります。

次のスタックが表示されます。スレッドのステータスはRUNNABLEです。呼び出しスタックは、SocketInputStreamまたはSocketImpl、socketRead0およびその他のメソッド上にあります。コールスタックには、jdbc関連のパッケージが含まれています。データベースのデッドロックが発生した可能性があります


"d&a-614" daemon prio=6 tid=0x0000000022f1f000 nid=0x37c8 runnable
[0x0000000027cbd000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at oracle.net.ns.Packet.receive(Packet.java:240)
at oracle.net.ns.DataPacket.receive(DataPacket.java:92)
at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:172)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:117)
at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1034)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:588)

スレッドスケジューリングでスリープ

通常のスレッドプール待機


"d&a-131" in Object.wait()
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo(WorkingManager.java:322)
- locked <0x0000000313f656f8> (a com.jiuqi.dna.core.impl.WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run(WorkingThread.java:40)

不審なスレッドが待機しています


"d&a-121" in Object.wait()
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at com.jiuqi.dna.core.impl.AcquirableAccessor.exclusive()
- locked <0x00000003011678d8> (a com.jiuqi.dna.core.impl.CacheGroup)
at com.jiuqi.dna.core.impl.Transaction.lock()

開始点の概要

モニターのエントリを待つ:ブロックされています。問題があるはずです

実行可能:IOスレッドに注意してください

Object.wait()内:スレッドプール以外の待機に注意してください

使用する


コマンドを学習したい場合は、最初にヘルプを確認してください。jstack-helpを使用してヘルプを表示します。

hollis@hos:~$ jstack -help
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

-F対応する 'jstack [-l] pid' -l long listがない場合に、スタック情報を強制的に出力します。java.util.concurrentに属する所有可能なシンクロナイザーのリストなどのロックに関する追加情報を出力します。-mprintjavaおよびnativec / c ++フレームワークすべてのスタック情報。-h| -helpヘルプ情報の印刷pid構成情報を印刷する必要があるjavaプロセスのID。jpsを使用してクエリを実行できます。

まず、そのようなプログラムのスレッドの状況を分析します。


/**
 * @author hollis
 */
public class JStackDemo1 {
    public static void main(String[] args) {
        while (true) {
            //Do Nothing
        }
    }
}

まず、プロセス番号を表示するjpsがあります。

hollis@hos:~$ jps
29788 JStackDemo1
29834 Jps
22385 org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar

次に、jstackを使用してスタック情報を表示します。

hollis@hos:~$ jstack 29788
2015-04-17 23:47:31
...此处省略若干内容...
"main" prio=10 tid=0x00007f197800a000 nid=0x7462 runnable [0x00007f197f7e1000]
   java.lang.Thread.State: RUNNABLE
    at javaCommand.JStackDemo1.main(JStackDemo1.java:7)

このスタック情報から何がわかりますか?現在、実行可能な状態にあり、JStackDemo1.javaの7行目まで実行されるユーザーレベルのスレッドがあることがわかります。次のコードを見てください。


/**
 * @author hollis
 */
public class JStackDemo1 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Thread1());
        thread.start();
    }
}
class Thread1 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println(1);
        }
    }
}

スレッドスタック情報は次のとおりです。

"Reference Handler" daemon prio=10 tid=0x00007fbbcc06e000 nid=0x286c in Object.wait() [0x00007fbbc8dfc000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x0000000783e066e0> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:503)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
    - locked <0x0000000783e066e0> (a java.lang.ref.Reference$Lock)

見える:

スレッドステータス:WAITINGスレッドのコールスタックスレッドの現在ロックされているリソース:<0x0000000783e066e0>現在リソースを待機しているスレッド:<0x0000000783e066e0>

同じリソースが同時にロックされるのを待っているのはなぜですか。

スレッドの実行では、このオブジェクトのモニターが最初に取得されます(ロックされた<0x0000000783e066e0>に対応)。実行がobj.wait()に達すると、スレッドはモニターの所有権を放棄し、「待機セット」キューに入ります(<0x0000000783e066e0>での待機に対応)。

デッドロック分析

jstackコマンドの使用方法を学習すると、jstackを使用してデッドロックを分析する方法を確認できます。これをマスターする必要があります。デッドロックとは何ですか?いわゆるデッドロックとは、リソースの競合や、2つ以上のプロセスの実行中の相互の通信によって引き起こされるブロッキング現象を指し、外力がないと前進できません。このとき、システムがデッドロック状態にある、またはシステムにデッドロックがあると言われ、常に互いに待機しているこれらのプロセスをデッドロックプロセスと呼びます。率直に言って、卵入りのパンケーキを食べたいです。テーブルには卵とパンケーキがありますが、友達と一緒に卵を拾って病気になりました。手には卵がありますが、彼の手にはパンケーキが必要です。彼は手にパンを持っていますが、私の手に卵が欲しいのです。このように、卵とパイを同時に手に入れることができないと、次の作業(卵を詰めるパイを作る)を続けることができなくなります。したがって、これはデッドロックを引き起こしました。行き詰まったプログラムを見てください:

package javaCommand;
/**
 * @author hollis
 */
public class JStackDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(new DeadLockclass(true));//建立一个线程
        Thread t2 = new Thread(new DeadLockclass(false));//建立另一个线程
        t1.start();//启动一个线程
        t2.start();//启动另一个线程
    }
}
class DeadLockclass implements Runnable {
    public boolean falg;// 控制线程
    DeadLockclass(boolean falg) {
        this.falg = falg;
    }
    public void run() {
        /**
         * 如果falg的值为true则调用t1线程
         */
        if (falg) {
            while (true) {
                synchronized (Suo.o1) {
                    System.out.println("o1 " + Thread.currentThread().getName());
                    synchronized (Suo.o2) {
                        System.out.println("o2 " + Thread.currentThread().getName());
                    }
                }
            }
        }
        /**
         * 如果falg的值为false则调用t2线程
         */
        else {
            while (true) {
                synchronized (Suo.o2) {
                    System.out.println("o2 " + Thread.currentThread().getName());
                    synchronized (Suo.o1) {
                        System.out.println("o1 " + Thread.currentThread().getName());
                    }
                }
            }
        }
    }
}

class Suo {
    static Object o1 = new Object();
    static Object o2 = new Object();
}

プログラムを開始すると、コンソールが表示されます。
Javaコマンド学習シリーズ(2つ)-Jstack

プログラムは2行しか出力せず、プログラムは他のものを出力しなくなりましたが、プログラムは停止しませんでした。これにより、デッドロックが発生します。スレッド1が同期を使用してo1をロックする場合、スレッド2も同期を使用してo2をロックします。両方のスレッドが最初の印刷タスクを終了すると、スレッド1はo2をロックし、スレッド2はo1をロックします。ただし、現在、スレッド1はo1をロックし、スレッド2はo2をロックします。したがって、二人は成都が処刑を続けることができず、行き詰まりを引き起こしたと考えている。

次に、jstackを使用してスレッドスタック情報を確認します。

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f0134003ae8 (object 0x00000007d6aa2c98, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f0134006168 (object 0x00000007d6aa2ca8, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at javaCommand.DeadLockclass.run(JStackDemo.java:40)
    - waiting to lock <0x00000007d6aa2c98> (a java.lang.Object)
    - locked <0x00000007d6aa2ca8> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at javaCommand.DeadLockclass.run(JStackDemo.java:27)
    - waiting to lock <0x00000007d6aa2ca8> (a java.lang.Object)
    - locked <0x00000007d6aa2c98> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

ハハ、スタックは明確に書かれています。これは、Javaレベルのデッドロックが1つ見つかったことを示し、デッドロックの原因となった2つのスレッドの内容を示しています。次に、上記のスレッドのJavaスタック情報を使用して、より詳細なデッドロック情報を表示します。彼は言った

Thread-1が行40を実行しようとすると、現在リソース<0x00000007d6aa2ca8>をロックしますが、リソース<0x00000007d6aa2c98>を待機しています。Thread-0が行27を実行しようとすると、現在リソース<0x00000007d6aa2c98をロックします。 >、しかし彼はリソースを待っています<0x00000007d6aa2ca8>これらの2つのスレッドは両方ともリソースを保持し、両方が互いにリソースを必要とするため、デッドロックが発生します。理由がわかれば、特定の問題を分析して行き詰まりを解消することができます。

その他

仮想マシンがフルGCを実行すると、すべてのユーザースレッドがブロックされます。したがって、同期ロックをすぐに取得するスレッドもブロックされる可能性があります。スレッドダンプを表示するときは、最初にメモリ使用量を確認してください。

おすすめ

転載: blog.51cto.com/13626762/2545872