Webサイト制作コースのお申し込みはこちら

Javaで長時間が処理が終わらない、異常にメモリを消費しているなど、IT エンジニアであれば、こうしたアプリケーションのトラブルに出会ったことがある人は少なくないでしょう。

この記事では、アプリケーションのトラブル調査に役立つ、Java のスレッドダンプの取り方と、取得したダンプの見方について解説していきます。

スレッドダンプとは?

スレッドダンプとは、指定した Java プロセスの、ある時点においての全スレッドの情報を出力したファイルです。

スレッドダンプには、すべてのスレッドのスタックトレースの情報が出力され、さらにデットロックなどが発生していれば、その情報も出力されます。

マルチスレッドで動作する Web アプリケーションでは、同時に複数のスレッドが動作しています。スレッドダンプを出力することで、それらのスタックトレースの状況を確認し、アプリケーションのボトルネックとなっている原因などを調査します。

テスト用プログラム

今回は次のサンプルコードを実行して、複数のスレッド情報を、スレッドダンプに出力してみましょう。

import java.util.concurrent.*;

public class Main {

  public static void main(String[] args) throws InterruptedException {
    //スレッドプールの作成
    ExecutorService pool = Executors.newFixedThreadPool(5);

    //5つのスレッド作成
    for (int cnt = 0; cnt < 5; cnt++) {
      pool.submit(() -> {
        for (int i = 0; i < 1800; i++) {
          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
          }
        }
      });
    }

    try {
      //すべてのスレッドが終了するまで、ここで待機する
      pool.shutdown();
      pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

スレッドダンプを取得してみよう

スレッドダンプは jstack コマンドを用いて取得します。

Java のプロセスIDを特定する

jstack コマンドは、動作中の JavaプロセスIDを指定してスレッドダンプを出力するため、まずはダンプを出力するプロセスのIDを特定する必要があります。

上で書いたサンプルコードを実行した状態で、jps コマンドで実行中の Java プロセスを確認します。

$ jps

81824 Jps
79596 org.eclipse.equinox.launcher_1.6.200.v20210416-2027.jar
81822 Main

複数の Java プロセスが実行中だと、上のように複数行の結果が出力されます。サンプルコードのプロセス名は「Main」で出力されるため、プロセスID=81822 をメモしておきます。

特定したプロセスIDでスレッドダンプを出力する

jps コマンドでプロセスが特定できたら、jstack コマンドにプロセスIDを指定してスレッドダンプを出力しましょう。

$ jstack <プロセスID>

jstack コマンドを実行すると、次のような結果が出力されます。

ダンプの中身を確認してみよう

初めてスレッドダンプを見ると、大量の文字が出力され、とまどうかもしれませんが、出力されたファイルを上から順を追って見ていきましょう。

スレッド ダンプの先頭

スレッド ダンプの先頭には、ヘッダー情報としてダンプを出力した日時や、使用されている JRockit JVM のバージョン番号が出力されます。

2021-09-12 16:14:36
Full thread dump OpenJDK 64-Bit Server VM (16.0.1+9 mixed mode, sharing):

スレッドのリスト

次に出力されるのが、実行中のスレッドIDのリストが出力されます。

Threads class SMR info:
_java_thread_list=0x00007fae1ff0dbb0, length=17, elements={
0x00007fae20008200, 0x00007fae2101d000, 0x00007fae2101f800, 0x00007fae2009a800,
0x00007fae2009ae00, ...
}
ポテパンダの一言メモ

スレッドIDのリストには、メインスレッドおよび、メインスレッドから起動したスレッドと、JVM がバックグラウンドで実行するガベージコレクションコレクションなどのデーモンスレッドのIDも出力されます。

スタックトレース情報

スレッドリストの次は、メインスレッドのスタックトレースが出力されます。

続けて、メインスレッド以外のスレッド情報と、JVM のバックグラウンドスレッドのスタックトレースの情報が出力されます。

デットロックの情報

プロセスでデットログが発生していると、スレッドダンプにはデットログックを引き起こしているスレッドIDの情報が出力されます。

デットロックは、普通のプログラムテストでは中々気付くことが難しく、本番環境で発生してしまうことがあります。このようなトラブル時にスレッドダンプを出力することで、デットロックの発生をすぐさま検知することができ、素早く問題への対処が行えます。

Found one Java-level deadlock:
=============================
"pool-1-thread-1":
  waiting to lock monitor 0x00007f853a71c9e0 (object 0x0000000787f1b740, a java.lang.Object),
  which is held by "pool-1-thread-2"

"pool-1-thread-2":
  waiting to lock monitor 0x00007f853a43d470 (object 0x0000000787f1b730, a java.lang.Object),
  which is held by "pool-1-thread-1"

Java stack information for the threads listed above:
===================================================

スレッドダンプを取得する時のポイント

アプリケーショントラブル時に、原因究明に役立つスレッドダンプを取得する時のポイントは次のとおりです。

数秒おきに複数回取る

スレッドダンプは数秒間隔で複数回取るようにしましょう。1回だけだと、偶然ネットワークアクセスが発生してスレッドが一時停止し、それがアプリケーションのボトルネックとして勘違いしてしまうことがあるため、何度か取得し、出力されたスタックトレースなどの情報から、共通している情報を抽出し、ボトルネックの調査に役立てます。

jstack プロセスID >  threaddump.$(date +%F-%H%m%S)

ヒープダンプも出来れば合わせて取りたい

Java にはスレッドダンプに似たものとして、現在のメモリ情報を出力ヒープダンプがあります。ヒープダンプとスレッドダンプを組み合わせて取得することで、より情報が揃っている状態で調査を進められるため、できれば合わせて取得しておきたいところです。

しかし、ヒープダンプはメモリ情報をダンプに出力する際にアプリケーションが一時的に停止するため、取得する時は注意が必要です。(スレッドダンプは取得時にアプリケーションを停止せず、それほぞ思い処理でもないため、積極的に取ることをお勧めします)

【関連記事】
【Java】wait・notifyを使ってスレッド間の待ち合わせを実装する

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。