1. 概要

このチュートリアルでは、Javaアプリケーションのスレッドダンプをキャプチャするさまざまな方法について説明します。

スレッドダンプは、Javaプロセスのすべてのスレッドの状態のスナップショットです。 各スレッドの状態は、スレッドのスタックの内容を示すスタックトレースで表示されます。 スレッドダンプは、スレッドのアクティビティを表示するため、問題の診断に役立ちます。 スレッドダンプはプレーンテキストで記述されているため、その内容をファイルに保存して、後でテキストエディタで確認できます

次のセクションでは、スレッドダンプを生成するための複数のツールとアプローチについて説明します。

2. JDKユーティリティの使用

JDKは、Javaアプリケーションのスレッドダンプをキャプチャできるいくつかのユーティリティを提供します。 すべてのユーティリティは、JDKホームディレクトリ内のbinフォルダの下にあります。 したがって、このディレクトリがシステムパスにある限り、コマンドラインからこれらのユーティリティを実行できます。

2.1. jstack

jstack は、スレッドダンプをキャプチャするために使用できるコマンドラインJDKユーティリティです。 プロセスのpidを取得し、コンソールにスレッドダンプを表示します。 または、出力をファイルにリダイレクトすることもできます。

jstackを使用してスレッドダンプをキャプチャするための基本的なコマンド構文を見てみましょう。

jstack [-F] [-l] [-m] <pid>

すべてのフラグはオプションです。 それらが何を意味するか見てみましょう:

  • -F オプションは、スレッドダンプを強制します。 jstack pid が応答しない(プロセスがハングしている)場合に便利です
  • -l オプションは、ヒープとロックで所有可能なシンクロナイザーを探すようにユーティリティに指示します
  • -mオプション Javaスタックフレームに加えて、ネイティブスタックフレーム(CおよびC ++)を出力します

スレッドダンプをキャプチャし、結果をファイルにリダイレクトすることで、この知識を活用しましょう。

jstack 17264 > /tmp/threaddump.txt

jps コマンドを使用すると、Javaプロセスのpidを簡単に取得できることに注意してください。

2.2. Javaミッションコントロール

Java Mission Control(JMC)は、Javaアプリケーションからデータを収集して分析するGUIツールです。 JMCを起動すると、ローカルマシンで実行されているJavaプロセスのリストが表示されます。 JMCを介してリモートJavaプロセスに接続することもできます。

プロセスを右クリックして、「フライトレコーディングの開始」オプションをクリックします。 この後、スレッドタブにスレッドダンプが表示されます。

2.3. jvisualvm

jvisualvmは、Javaアプリケーションの監視、トラブルシューティング、およびプロファイリングを可能にするグラフィカルユーザーインターフェイスを備えたツールです。 GUIはシンプルですが、非常に直感的で使いやすいです。

その多くのオプションの1つにより、スレッドダンプをキャプチャできます。 Javaプロセスを右クリックし、「スレッドダンプ」オプションを選択すると、ツールはスレッドダンプを作成し、新しいタブで開きます。

JDK 9の時点では、VisualVMはOracleJDKおよびOpenJDKディストリビューションに含まれていません。 したがって、Java 9以降のバージョンを使用している場合は、VisualVMオープンソースプロジェクトサイトからJVisualVMを入手できます。

2.4. jcmd

jcmd は、JVMにコマンド要求を送信することによって機能するツールです。 強力ですが、にはリモート機能が含まれていません。Javaプロセスが実行されているのと同じマシンで使用する必要があります。

その多くのコマンドの1つはThread.printです。 プロセスのpidを指定するだけで、スレッドダンプを取得するために使用できます。

jcmd 17264 Thread.print

2.5. jconsole

jconsole を使用すると、各スレッドのスタックトレースを検査できます。 jconsole を開いて、実行中のJavaプロセスに接続すると、 [スレッド]タブに移動して、各スレッドのスタックトレースを見つけることができます。

2.6. 概要

実は、JDKユーティリティを使用してスレッドダンプをキャプチャする方法はたくさんあります。 それぞれについて振り返り、それぞれの長所と短所の概要を説明しましょう。

  • jstack :スレッドダンプをキャプチャするための最も速くて簡単な方法を提供します。 ただし、Java8以降のより優れた代替手段が利用可能です。
  • jmc :拡張されたJDKプロファイリングおよび診断ツール。 これにより、プロファイリングツールで通常問題となるパフォーマンスのオーバーヘッドが最小限に抑えられます。
  • jvisualvm :優れたGUIコンソールを備えた軽量でオープンソースのプロファイリングツール
  • jcmd :非常に強力で、Java8以降に推奨されます。 スレッドダンプ( jstack )、ヒープダンプ( jmap )、システムプロパティ、およびコマンドライン引数( jinfo )のキャプチャなど、多くの目的に役立つ単一のツール
  • jconsole :スレッドスタックトレース情報を検査できます

3. コマンドラインから

エンタープライズアプリケーションサーバーでは、セキュリティ上の理由からJREのみがインストールされます。 したがって、上記のユーティリティはJDKの一部であるため、使用できません。 ただし、スレッドダンプを簡単にキャプチャできるさまざまなコマンドラインの選択肢があります。

3.1. kill -3コマンド(Linux / Unix)

Unixライクなシステムでスレッドダンプをキャプチャする最も簡単な方法は、 kill コマンドを使用することです。このコマンドを使用して、 kill()システムコールを使用してプロセスにシグナルを送信できます。 このユースケースでは、-3信号を送信します。

前の例と同じpidを使用して、killを使用してスレッドダンプをキャプチャする方法を見てみましょう。

kill -3 17264

このようにして、信号受信Javaプロセスは、スレッドダンプを標準出力に出力します。

次のチューニングフラグの組み合わせを使用してJavaプロセスを実行すると、スレッドダンプも指定されたファイルにリダイレクトされます。

-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=~/jvm.log

ここで、 -3 信号を送信すると、標準出力に加えて、ダンプは〜/jvm.logファイルで利用できるようになります。

3.2. Ctrl + Break(Windows)

Windowsオペレーティングシステムでは、CTRLキーとBreakキーの組み合わせを使用してスレッドダンプをキャプチャできます。 スレッドダンプを取得するには、Javaアプリケーションの起動に使用したコンソールに移動し、CTRLキーとBreakキーを同時に押します。

一部のキーボードでは、Breakキーが使用できないことに注意してください。 したがって、このような場合は、 CTRL SHIFT 、およびPauseキーを同時に使用してスレッドダンプをキャプチャできます。

これらのコマンドは両方とも、スレッドダンプをコンソールに出力します。

4. プログラムでThreadMxBeanを使用する

この記事で説明する最後のアプローチは、JMXを使用することです。 ThreadMxBeanを使用してスレッドダンプをキャプチャします。 コードで見てみましょう:

private static String threadDump(boolean lockedMonitors, boolean lockedSynchronizers) {
    StringBuffer threadDump = new StringBuffer(System.lineSeparator());
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {
        threadDump.append(threadInfo.toString());
    }
    return threadDump.toString();
}

上記のプログラムでは、いくつかの手順を実行しています。

  1. 最初に、空の StringBuffer が初期化され、各スレッドのスタック情報が保持されます。
  2. 次に、 ManagementFactory のインスタンスを取得するクラス ThreadMxBean。 A ManagementFactory Javaプラットフォーム用のマネージドBeanを取得するためのファクトリクラスです。 さらに、 ThreadMxBean は、JVMのスレッドシステムの管理インターフェイスです。
  3. lockedMonitorsおよびlockedSynchronizersの値をtrueに設定すると、所有可能なシンクロナイザーとすべてのロックされたモニターがスレッドダンプにキャプチャされます。

5. 結論

この記事では、スレッドダンプをキャプチャする複数の方法を学びました。

最初に、さまざまなJDKユーティリティについて説明し、次にコマンドラインの代替案について説明しました。 最後に、JMXを使用したプログラムによるアプローチで締めくくりました。

いつものように、例の完全なソースコードは、GitHubから入手できます。