JavaツールJstackの使用

jstack-Javaプロセス、コアファイル、またはリモートデバッグサーバーのJavaスレッドスタックトレースを出力します。

Jstackの主な機能は、現在のプロセスのすべてのスレッドに関する情報、つまり、現時点でのJVMのスレッドスナップショットを生成することです。スレッド情報を通じて、長い一時停止や高いCPU使用率などの問題を特定できます。プログラム。

スレッドスナップショットの情報は、現在のJava仮想マシンの各スレッドによって実行されているメソッドのスタックコレクションです。スタック情報を使用すると、スレッド間のデッドロック、外部リソース要求の経過時間など、プログラムの問題が発生する場所を分析できます。長い、無限のループなど。

使用する:

jstack [ options ] pid

jstack [ options ] executable core

jstack [ options ] [ server-id@ ] remote-hostname-or-IP


OPTIONS
       -F
              Force a stack dump when jstack [-l] pid does not respond.

       -l
              Long listing. Prints additional information about locks such as a list of owned java.util.concurrent ownable synchronizers. See the
              AbstractOwnableSynchronizer class description at
              http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/AbstractOwnableSynchronizer.html

       -m
              Prints a mixed mode stack trace that has both Java and native C/C++ frames.
  • -F通常の要求に応答しない場合に、スタック情報を強制的に出力します。
  • -l追加の印刷ロック情報。デッドロックが発生すると、ロック情報を表示できます。
  • -mネイティブメソッドスタックの情報を呼び出すと、C /C++スタックを出力できます

デッドロックの例を見て、Jstackを使用して表示された情報を確認します

public class Jstack {
    
    

    private static Object obj1 = new Object();
    private static Object obj2 = new Object();

    public static void main(String[] args) {
    
    

        new Thread(() -> {
    
    
            synchronized (obj1) {
    
    
                try {
    
    
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                synchronized (obj2) {
    
    
                }
            }
        }).start();
        new Thread(() -> {
    
    
            synchronized (obj2) {
    
    
                try {
    
    
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                synchronized (obj1) {
    
    
                }
            }
        }).start();
    }
}

上記のコードでは、最初のスレッドがobj1のロックを取得してobj2のロックを待機し、2番目のスレッドがobj2のロックを取得してobj1のロックを待機するため、デッドロックが発生します。

最初にコマンドを介しjpsて現在のプロセスpidを取得し、次にjstackを介してスレッド情報を取得します。両方のスレッドがブロックされていることがわかります。

"Thread-1" #12 prio=5 os_prio=0 tid=0x00007fdff871c800 nid=0x3cc2 waiting for monitor entry [0x00007fdfce0fc000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.example.demo.jstack.Jstack.lambda$main$1(Jstack.java:36)
	- waiting to lock <0x000000076e925a90> (a java.lang.Object)
	- locked <0x000000076e925aa0> (a java.lang.Object)
	at com.example.demo.jstack.Jstack$$Lambda$2/2052001577.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

"Thread-0" #11 prio=5 os_prio=0 tid=0x00007fdff871a800 nid=0x3cc1 waiting for monitor entry [0x00007fdfce1fc000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.example.demo.jstack.Jstack.lambda$main$0(Jstack.java:25)
	- waiting to lock <0x000000076e925aa0> (a java.lang.Object)
	- locked <0x000000076e925a90> (a java.lang.Object)
	at com.example.demo.jstack.Jstack$$Lambda$1/1174361318.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

最初の行には、スレッド名、スレッドの優先度、スレッドID、スレッドの状態の説明などの情報が表示されます。

2行目は、現在のスレッドのステータスを示しています

Javaのスレッドのステータスは、NEW、RUNNABLE、BLOCKED、WATING、TIMED_WATING、TERMINATEDに分けられますが、NEWステータスはスナップショットに表示されません。

以下は、現在のスレッドの呼び出しスタックの情報です。コールスタックにはロック情報が含まれています。

locked同期を使用してオブジェクト

waiting to lock同期を使用したオブジェクトロックの申請が失敗し、待合室に入ったことを示します

waiting on同期されたオブジェクトロックの適用に成功した後、待機メソッドが呼び出されて、待機するオブジェクトの待機領域に入ることを示します

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

最後に、コードにデッドロックがあるというメッセージも表示されます

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007fdfac006638 (object 0x000000076e925a90, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007fdfac003da8 (object 0x000000076e925aa0, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
	at com.example.demo.jstack.Jstack.lambda$main$1(Jstack.java:36)
	- waiting to lock <0x000000076e925a90> (a java.lang.Object)
	- locked <0x000000076e925aa0> (a java.lang.Object)
	at com.example.demo.jstack.Jstack$$Lambda$2/2052001577.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)
"Thread-0":
	at com.example.demo.jstack.Jstack.lambda$main$0(Jstack.java:25)
	- waiting to lock <0x000000076e925aa0> (a java.lang.Object)
	- locked <0x000000076e925a90> (a java.lang.Object)
	at com.example.demo.jstack.Jstack$$Lambda$1/1174361318.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

Jstackに精通しているので、コードの無限ループを使用して、CPUがJstackを介して100%占有するコード行を特定します。

public class JstackDemo {
    
    
    public static Executor executor = Executors.newFixedThreadPool(3);
    private static Object lock = new Object();

    public static void main(String[] args) {
    
    
        Task task1 = new Task();
        Task task2 = new Task();
        executor.execute(task1);
        executor.execute(task2);
    }

    public static class Task implements Runnable {
    
    

        @Override
        public void run() {
    
    
            synchronized (lock) {
    
    
                run0();
            }
        }

        private void run0() {
    
    
            int i = 0;
            while (true) {
    
    
                i++;
            }
        }
    }
}

1.まず、topCPUが100%を占めるようにするプロセスIDを表示します

2.top -Hp 进程id最も多くのCPUを占有するスレッドIDを表示するために使用します

3.スレッドIDを16進数に変換します

17997-> 464d

4. Jstackを使用して、Javaが配置されているプロセスを表示し、対応するスレッドを見つけます

おすすめ

転載: blog.csdn.net/y5492853/article/details/124456091