スレッド ダンプの生成

複数製品に共通のナレッジ

このページの内容

お困りですか?

アトラシアン コミュニティをご利用ください。

コミュニティに質問

ご利用のアトラシアン アプリケーションが応答を返さなくなったり、アトラシアン アプリケーションのパフォーマンスが低下したりした場合に、アトラシアン サポートで問題の診断のためにスレッド ダンプの提供を依頼させていただくことがあります。スレッド ダンプは、Java 仮想マシン内で現在実行されているスレッドとプロセスの情報を含むログです。スレッド ダンプの取得は非破壊プロセスであるため、実行中のシステム上で実施することができます。このドキュメントでは、スレッド ダンプの取得に必要な手順を説明します。

スレッド ダンプの取得に必要な手順は、サーバーのオペレーティング システム (Windows または Linux) に応じて異なります。また、スレッド ダンプを手動で取得することも、サポート スクリプトを使用してスレッド ダンプを自動的に取得することもできます。お客様の支援のためにサポートで必要となる情報を取得できるように設計されている、サポート スクリプトの使用をおすすめします。

スレッドを時間別に比較できるよう、一連のスレッド ダンプを生成することをおすすめします。アトラシアン サポートでは一般に、1 分間で 10 秒間隔のスレッド ダンプを 6 つ取得することを推奨しています。

スレッド ダンプの自動生成

Windows and Linux environment using Java Flight Recorder (JFR)

JFR is bundled in the following Atlassian applications (via Troubleshooting and Support Tools app), and continuous diagnostic data recording begins as soon as you start up your instance:

  • Jira Data Center and Server 9.0 and newer

  • Bitbucket Data Center and Server 8.3 and newer

  • Confluence Data Center and Server 7.20 and newer

Thread dumps are a part of the diagnostic data that is automatically captured by JFR. Within our applications, we've changed the default frequency for gathering thread dumps to once every 10 seconds.
This set of thread dumps would then be automatically saved to a binary .jfr file (in <Application-Home-Directory>/log/jfr folder) every five minutes, together with the other diagnostics data (runtime events). Collected thread dumps within the binary .jfr file would need to be parsed using JDK Mission Control.

In addition to that, when a Support zip is being created, a new binary .jfr file would be created in the <Application-Home-Directory>/log/jfr folder as well.
This latest .jfr binary file and thread dumps that are extracted from it will be included in the Support zip file (under jfr-bundle folder). This set of extracted thread dumps are already in human-readable format and can be parsed by common thread analysis tools.

(info) For more information on this, please refer to our Diagnosing runtime issues using the Java Flight Recorder documentation.

スレッド ダンプの手動生成

Windows 環境

次の手順にしたがってスレッド ダンプを手動で取得します。

The application running in the console window

  1. In the Command Console window where the application is running, open the properties dialog box by right-clicking on the title bar and selecting "Properties".
  2. [Layout] タブを選択します。
  3. [Screen Buffer Size] で、[Height] を 3000 に設定します。
  4. [OK] をクリックします。
  5. 同じコマンド コンソールで CTRL-BREAK を押すと、コマンド コンソールにスレッド ダンプが出力されます。
  6. "Full thread dump" と書かれた行まで、コマンド コンソールをスクロールします。
  7. Right-click the title bar and select Edit -> Mark. Highlight the entire text of the thread dump.
  8. Right-click the title bar and select Edit -> Copy. The thread dump can then be pasted into a text file.

The application runs as a Windows Service

jstack を使用する場合

JDK には‬ jstack という名前の、スレッド ダンプ生成用のツールが付属します。

If you're using the JVM bundled with the product, please download and install a supported JDK, such as AdoptOpenJDK.
(info) Please make sure that the JDK is of the same major version as the JVM running the application, typically Java 8 or 11. If in doubt, run java -version to check

  1. Launch Windows Powershell as administrator
  2. Run this command to set the PID to a variable

    $APP_PID = (Get-Process -name "tomcat8.exe.x64").id

    Alternatively, launch the task manager by, pressing Ctrl + Shift + Esc and find the Process ID of the Java process. You may need to add the PID column using View -> Select Columns ...
    (info) 
    If there are multiple Tomcat/application instances running, please get the PID manually for the right process.

  3. Run this 

    1..6|foreach{jstack -l $APP_PID|Out-File -FilePath "app_threads.$(Get-Date -uformat %s).txt";sleep 10}

    This will create the app_threads files in the current directory.


‪ jstack‬ のよくある問題

  • You must run jstack as an admin or as the same user that is running the application.
  • エラー メッセージ "Not enough storage is available to process this command" が表示された場合、ここから‪ "psexec" ユーティリティをダウンロードして、以下のコマンドを実行します。
    psexec -s jstack <pid> >> threaddumps.txt
  • If you are connecting to the server through RDP and getting "Not enough storage is available to process this command", you will need to open an RDP session in console mode: 
    mstsc /admin
  • If the jstack executable is not in your $PATH, then please look for it in your <JDK_HOME>/bin directory
  • java.lang.NoClassDefFoundError: sun/tools/jstack/JStack が発生したら、JDK の lib ディレクトリに tools.jar があるかどうかを確認します。存在しない場合、JDK の完全なバージョンをダウンロードします (プロセスが実行されている JRE と同じバージョンの JDK をダウンロードするようにします)。

Linux / Unix / OS X 環境

Using jstack

これはスレッドとそれらの CPU 使用率の両方を提供するため、推奨される手法です。jstack は指定されたプロセスの Java スレッドのスタック トレースを出力する、java ユーティリティです。jstack に同梱される JDK がサーバーに必要です。

  1. アプリケーションが実行されている Java プロセスを特定し、それを APP_PID 環境変数に格納します。

    Bamboo Server
    APP_PID=`ps aux | grep -i bamboo | grep -i java | awk  -F '[ ]*' '{print $2}'`;
    APP_USER=`ps aux | grep -i bamboo | grep -i java | awk  -F '[ ]*' '{print $1}'`;
    Bitbucket Server
    APP_PID=`ps aux | grep -i bitbucket | grep -i java | awk  -F '[ ]*' '{print $2}'`;
    APP_USER=`ps aux | grep -i bitbucket | grep -i java | awk  -F '[ ]*' '{print $1}'`;
    Confluence
    APP_PID=`ps aux | grep -i confluence | grep -i java | awk  -F '[ ]*' '{print $2}'`;
    APP_USER=`ps aux | grep -i confluence | grep -i java | awk  -F '[ ]*' '{print $1}'`;
    Fisheye/Crucible
    APP_PID=`ps aux | grep -i fisheye | grep -i java | awk  -F '[ ]*' '{print $2}'`;
    APP_USER=`ps aux | grep -i fisheye | grep -i java | awk  -F '[ ]*' '{print $1}'`;
    Jira
    APP_PID=`ps aux | grep -i jira | grep -i java | awk  -F '[ ]*' '{print $2}'`;
    APP_USER=`ps aux | grep -i jira | grep -i java | awk  -F '[ ]*' '{print $1}'`;
  2. 次のコマンドを実行します。

    # seq 6, will run the command 6 times
    # sleep 10, will wait for 10 seconds
    for i in $(seq 6); do top -b -H -p $APP_PID -n 1 > app_cpu_usage.`date +%s`.txt; jstack $APP_PID > app_threads.`date +%s`.txt; sleep 10; done

    アプリケーションをサービスとして実行している場合、次のコマンドを実行して、アプリケーション サービスを実行しているユーザーを確認します。

    # seq 6, will run the command 6 times
    # sleep 10, will wait for 10 seconds
    for i in $(seq 6); do top -b -H -p $APP_PID -n 1 > app_cpu_usage.`date +%s`.txt; sudo -u $APP_USER jstack $APP_PID > app_threads.`date +%s`.txt; sleep 10; done
  3. 現在のディレクトリに、app_cpu_usage.<DATE>.txt および app_threads.<DATE>.txt が結果として出力されます。

生成されたスレッド ダンプの分析
  • Look in the CPU usage files to identify which threads are consistently using a lot of CPU time

  • CPU 時間を使用している上位 10 個のスレッドの PID を記録し、それらを 16 進数に変換します。例: 11159 -> 0x2b97

  • 16 進数の値をスレッド ダンプで検索し、CPU を使用しているスレッドを特定します。

kill シグナルの使用

If the JDK and jstack are not available on the server, a kill signal can be sent to the Java process to produce a thread dump.

  1. アプリケーションが実行されている Java プロセスを特定します。これは以下のようなコマンドで実現できます。

    ps -ef | grep java

    次のようなプロセスが見つかります。

    keithb     910   873  1 17:01 pts/3    00:00:18 /usr/java/jdk/bin/java -Xms128m -Xmx256m
    -Xms128m -Xmx256m -Djava.awt.headless=true -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
    -Djava.awt.headless=true -Djava.endorsed.dirs=/tmp/atlassian-jira-enterprise-3.6-standalone/common/endorsed
    -classpath :
  2. スレッド ダンプを取得するには、次のコマンドを実行します。

    # seq 6, will run the command 6 times
    # sleep 10, will wait for 10 seconds
    for i in $(seq 6); do top -b -H -p $APP_PID -n 1 > app_cpu_usage.`date +%s`.txt; kill -3 $APP_PID ; sleep 10; done

    where $APP_PID is the process id — in this case, 910.

  3. スレッド ダンプが Tomcat のコンソール出力に記載されます。コンソール出力は logs/catalina.out ファイル (アプリケーション インストール ディレクトリにあります) にリダイレクトされます。

スレッド ダンプの分析のための一般的な分析ツール

Try TDA, IBM TMDA (JCA) or Samurai to inspect your thread dump.

TDA

  1. TDA をダウンロードします。
  2. JAR が存在するディレクトリに CD します。
  3. 次のコマンドを実行します。

    java -jar -Xmx512M ~/tda-bin-1.6/tda.jar
  4. スレッド ダンプを含む catalina.out ファイルを開きます。

TDA でスレッド ダンプを処理する場合の問題 (NumberFormatException)

Should you get an error on the TDA console like:

Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "5 os_prio=0"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.lang.Long.parseLong(Long.java:441)
        at java.lang.Long.<init>(Long.java:702)
        at com.pironet.tda.utils.ThreadsTableModel.getValueAt(ThreadsTableModel.java:80)
        at com.pironet.tda.utils.TableSorter.getValueAt(TableSorter.java:285)
        at javax.swing.JTable.getValueAt(JTable.java:2717)
        at javax.swing.JTable.prepareRenderer(JTable.java:5719)
        at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2114)
        at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
        at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
        at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
        at javax.swing.JComponent.paintComponent(JComponent.java:778)
        at javax.swing.JComponent.paint(JComponent.java:1054)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JViewport.paint(JViewport.java:731)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JSplitPane.paintChildren(JSplitPane.java:1047)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JComponent.paintToOffscreen(JComponent.java:5230)
        at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:295)
        at javax.swing.RepaintManager.paint(RepaintManager.java:1249)
        at javax.swing.JComponent._paintImmediately(JComponent.java:5178)
        at javax.swing.JComponent.paintImmediately(JComponent.java:4989)
        at javax.swing.RepaintManager$3.run(RepaintManager.java:808)
        at javax.swing.RepaintManager$3.run(RepaintManager.java:796)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:769)
        at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:718)
        at javax.swing.RepaintManager.access$1100(RepaintManager.java:62)
        at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1677)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
        at java.awt.EventQueue.access$200(EventQueue.java:103)
        at java.awt.EventQueue$3.run(EventQueue.java:694)
        at java.awt.EventQueue$3.run(EventQueue.java:692)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

これを処理可能にするには、スレッド ダンプに次のコマンドを適用して、スレッドのヘッダーの形式を修正します。

Linux
sed -i 's/prio=[0-9]\{1,2\} os_prio=-\?[0-9]\{1,2\}/prio=5/g' <filename> 
Mac
sed -i '' -E 's/prio=[0-9]{1,2} os_prio=-?[0-9]{1,2}/prio=5/g' <filename>

最終更新日 2023 年 4 月 17 日

この内容はお役に立ちましたか?

はい
いいえ
この記事についてのフィードバックを送信する
Powered by Confluence and Scroll Viewport.