プロセッサにロードしているJavaスレッド

JavaアプリケーションがCPUの100%を消費する場合はどうしますか? 組み込みのUnixおよびJDKユーティリティを使用すると、問題のあるスレッドを簡単に見つけることができます。 プロファイリングツールは必要ありません。

テストのために、単純なプログラムを使用します。



public class Main { public static void main(String[] args) { new Thread(new Idle(), "Idle").start(); new Thread(new Busy(), "Busy").start(); } } class Idle implements Runnable { @Override public void run() { try { TimeUnit.HOURS.sleep(1); } catch (InterruptedException e) { } } } class Busy implements Runnable { @Override public void run() { while(true) { "Foo".matches("F.*"); } } }
      
      





ご覧のとおり、このコードでは2つのスレッドが起動されています。 アイドルはCPUリソースを消費しません(

スリープスレッドはメモリを消費しますが、プロセッサは消費しません)。一方、ビジーは正規表現やその他の複雑なプロセスを解析してCPUに大きな負荷をかけます。

プログラムで問題のあるコードをすばやく見つけるにはどうすればよいですか? 最初に、「top」を使用して、JavaアプリケーションのプロセスID(PID)を見つけます。 とても簡単です:

 top -n1 | grep -m1 java
      
      





「java」という単語を含む出力「top」の最初の行が表示されます。

 22614 tomek 20 0 1360m 734m 31m S 6 24.3 7:36.59 java
      
      





最初の列はPIDです。 残念ながら、「top」は色にANSIエスケープコードを使用していることが判明しました。 幸いなことに、余分な文字を削除して最終的にPIDを抽出するperlスクリプトを見つけました。

 top -n1 | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' '
      
      





戻り値:

 22614
      
      





プロセスのPIDがわかったので、top -Hを使用して問題のあるLinuxスレッドを検索できます。 -Hスイッチは、すべてのスレッドのリストを表示し、PID列はスレッドIDです。

 top -n1 -H | grep -m1 java top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' '
      
      





戻り値:

 25938 tomek 20 0 1360m 748m 31m S 2 24.8 0:15.15 java 25938
      
      





したがって、JVMプロセスIDとLinuxスレッドIDがあります。 そして今、楽しい部分のために:jstack(JDKで利用可能)の出力を見ると、各スレッドは名前の後に書かれたNIDを持っています。

 Busy' prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000] java.lang.Thread.State: RUNNABLE at java.util.regex.Pattern$Node.study(Pattern.java:3010)
      
      





パラメーターnid = 0x6552は、ストリームIDの16進表現です。

 printf '%x' 25938 6552
      
      





次に、すべてを1つのスクリプトに結合します。

 #!/bin/bash PID=$(top -n1 | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' ') NID=$(printf '%x' $(top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' ')) jstack $PID | grep -A500 $NID | grep -m1 '^$' -B 500
      
      





最後の行は、特定のPIDでjstackを開始し、一致するNIDのストリームを表示します。 同じフローには問題があります。

私たちは実施します:

 ./profile.sh "Busy" prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000] java.lang.Thread.State: RUNNABLE at java.util.regex.Pattern$Node.study(Pattern.java:3010) at java.util.regex.Pattern$Curly.study(Pattern.java:3854) at java.util.regex.Pattern$CharProperty.study(Pattern.java:3355) at java.util.regex.Pattern$Start.<init>(Pattern.java:3044) at java.util.regex.Pattern.compile(Pattern.java:1480) at java.util.regex.Pattern.<init>(Pattern.java:1133) at java.util.regex.Pattern.compile(Pattern.java:823) at java.util.regex.Pattern.matches(Pattern.java:928) at java.lang.String.matches(String.java:2090) at com.blogspot.nurkiewicz.Busy.run(Main.java:27) at java.lang.Thread.run(Thread.java:662)
      
      







出所




All Articles