69

Javaプログラムが100%CPUを使用しているとしましょう。50スレッドあります。どのスレッドが有罪かを見つける必要があります。役立つツールは見つかりませんでした。現在、私は次の非常に時間のかかるルーチンを使用しています。

  1. を実行しますjstack <pid>。ここで、pidはJavaプロセスのプロセスIDです。それを見つける簡単な方法は、JDKに含まれている別のユーティリティを実行することです- jps。jstackの出力をファイルにリダイレクトすることをお勧めします。
  2. 「実行可能な」スレッドを検索します。ソケットで待機しているものをスキップします(何らかの理由で、まだ実行可能とマークされています)。
  3. 手順1と2を数回繰り返して、パターンを見つけることができるかどうかを確認します。

または、EclipseでJavaプロセスに接続し、CPUを占有するプロセスに到達するまで、スレッドを1つずつ中断してみることもできます。1 CPUマシンでは、移動できるようにするために、最初にJavaプロセスの優先度を下げる必要がある場合があります。それでも、Eclipseはタイムアウトのために、実行中のプロセスに接続できないことがよくあります。

visualvm私はSunのツールがこれを行うことを期待していました。

誰かがより良い方法を知っていますか?

4

12 に答える 12

89

本番サーバーで最も多くの CPU を消費している Java スレッドを特定します。

重要なことを行うほとんどの (すべてではないにしても) 生産システムは、複数の Java スレッドを使用します。そして、何かがおかしくなり、CPU 使用率が 100% になった場合、どのスレッドが原因であるかを特定するのは困難です。とか、そう思いました。私より賢い誰かがそれを行う方法を教えてくれるまで。そして、ここでその方法を紹介します。あなたも、オタクのスキルで家族や友人を驚かせることができます。

テスト アプリケーション

これをテストするには、テスト アプリケーションが必要です。だから私はあなたに1つあげます。次の 3 つのクラスで構成されます。

  • CPU を集中的に使用するHeavyThreadクラス (MD5 ハッシュの計算)
  • LightThreadそれほど CPU を使わない処理 (カウントとスリープ) を行うクラス。
  • StartThreads1 つの CPU を集中的に使用し、いくつかの軽いスレッドを開始するクラス。

これらのクラスのコードは次のとおりです。

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * thread that does some heavy lifting
 *
 * @author srasul
 *
 */
public class HeavyThread implements Runnable {

        private long length;

        public HeavyThread(long length) {
                this.length = length;
                new Thread(this).start();
        }

        @Override
        public void run() {
                while (true) {
                        String data = "";

                        // make some stuff up
                        for (int i = 0; i < length; i++) {
                                data += UUID.randomUUID().toString();
                        }

                        MessageDigest digest;
                        try {
                                digest = MessageDigest.getInstance("MD5");
                        } catch (NoSuchAlgorithmException e) {
                                throw new RuntimeException(e);
                        }

                        // hash the data
                        digest.update(data.getBytes());
                }
        }
}


import java.util.Random;

/**
 * thread that does little work. just count & sleep
 *
 * @author srasul
 *
 */
public class LightThread implements Runnable {

        public LightThread() {
                new Thread(this).start();
        }

        @Override
        public void run() {
                Long l = 0l;
                while(true) {
                        l++;
                        try {
                                Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                        if(l == Long.MAX_VALUE) {
                                l = 0l;
                        }
                }
        }
}


/**
 * start it all
 *
 * @author srasul
 *
 */
public class StartThreads {

        public static void main(String[] args) {
                // lets start 1 heavy ...
                new HeavyThread(1000);

                // ... and 3 light threads
                new LightThread();
                new LightThread();
                new LightThread();
        }
}

このコードを見たことがなく、これらのクラスを実行して 100% の CPU を消費しているランナウェイ Java プロセスの PID をすべて知っていると仮定します。

StartThreadsまずは授業を始めましょう。

$ ls
HeavyThread.java  LightThread.java  StartThreads.java
$ javac *
$ java StartThreads &

この段階で、実行中の Java プロセスは 100 cpu を占有しているはずです。私のトップには次のように表示されます。 トップ出力のスクリーンショット

一番上に Shift-H を押して、スレッドをオンにします。トップのマニュアルページには次のように書かれています:

   -H : Threads toggle
        Starts top with the last remembered 'H' state reversed.  When
        this  toggle is On, all individual threads will be displayed.
        Otherwise, top displays a  summation  of  all  threads  in  a
        process.

そして今、スレッド表示がオンになっている私のトップに、次のように表示されます。 スレッドが表示された上部のスクリーンショット

そしてjava、 PID を使用したプロセスがあります28294。以下を使用して、このプロセスのスタック ダンプを取得しますjstack

$ jstack 28924
2010-11-18 13:05:41
Full thread dump Java HotSpot(TM) 64-Bit Server VM (17.0-b16 mixed mode):

"Attach Listener" daemon prio=10 tid=0x0000000040ecb000 nid=0x7150 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" prio=10 tid=0x00007f9a98027800 nid=0x70fd waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-3" prio=10 tid=0x00007f9a98025800 nid=0x710d waiting on condition [0x00007f9a9d543000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at LightThread.run(LightThread.java:21)
    at java.lang.Thread.run(Thread.java:619)

"Thread-2" prio=10 tid=0x00007f9a98023800 nid=0x710c waiting on condition [0x00007f9a9d644000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at LightThread.run(LightThread.java:21)
    at java.lang.Thread.run(Thread.java:619)

"Thread-1" prio=10 tid=0x00007f9a98021800 nid=0x710b waiting on condition [0x00007f9a9d745000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at LightThread.run(LightThread.java:21)
    at java.lang.Thread.run(Thread.java:619)

"Thread-0" prio=10 tid=0x00007f9a98020000 nid=0x710a runnable [0x00007f9a9d846000]
   java.lang.Thread.State: RUNNABLE
    at sun.security.provider.DigestBase.engineReset(DigestBase.java:139)
    at sun.security.provider.DigestBase.engineUpdate(DigestBase.java:104)
    at java.security.MessageDigest$Delegate.engineUpdate(MessageDigest.java:538)
    at java.security.MessageDigest.update(MessageDigest.java:293)
    at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:197)
    - locked <0x00007f9aa457e400> (a sun.security.provider.SecureRandom)
    at sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:257)
    - locked <0x00007f9aa457e708> (a java.lang.Object)
    at sun.security.provider.NativePRNG$RandomIO.access$200(NativePRNG.java:108)
    at sun.security.provider.NativePRNG.engineNextBytes(NativePRNG.java:97)
    at java.security.SecureRandom.nextBytes(SecureRandom.java:433)
    - locked <0x00007f9aa4582fc8> (a java.security.SecureRandom)
    at java.util.UUID.randomUUID(UUID.java:162)
    at HeavyThread.run(HeavyThread.java:27)
    at java.lang.Thread.run(Thread.java:619)

"Low Memory Detector" daemon prio=10 tid=0x00007f9a98006800 nid=0x7108 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread1" daemon prio=10 tid=0x00007f9a98004000 nid=0x7107 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x00007f9a98001000 nid=0x7106 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x0000000040de4000 nid=0x7105 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x0000000040dc4800 nid=0x7104 in Object.wait() [0x00007f9a97ffe000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00007f9aa45506b0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x00007f9aa45506b0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x0000000040dbd000 nid=0x7103 in Object.wait() [0x00007f9a9de92000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00007f9aa4550318> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x00007f9aa4550318> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x0000000040db8800 nid=0x7102 runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x0000000040d6e800 nid=0x70fe runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x0000000040d70800 nid=0x70ff runnable 

"GC task thread#2 (ParallelGC)" prio=10 tid=0x0000000040d72000 nid=0x7100 runnable 

"GC task thread#3 (ParallelGC)" prio=10 tid=0x0000000040d74000 nid=0x7101 runnable 

"VM Periodic Task Thread" prio=10 tid=0x00007f9a98011800 nid=0x7109 waiting on condition 

JNI global references: 910

一番上から見ると、一番上のスレッドの PID は28938. そして2893816 進数では0x710A. スタック ダンプでは、各スレッドnidに 16 進数で表示されていることに注意してください。そして、たまたまそれ0x710Aがスレッドの id です。

"Thread-0" prio=10 tid=0x00007f9a98020000 nid=0x710a runnable [0x00007f9a9d846000]
   java.lang.Thread.State: RUNNABLE
    at sun.security.provider.DigestBase.engineReset(DigestBase.java:139)
    at sun.security.provider.DigestBase.engineUpdate(DigestBase.java:104)
    at java.security.MessageDigest$Delegate.engineUpdate(MessageDigest.java:538)
    at java.security.MessageDigest.update(MessageDigest.java:293)
    at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:197)
    - locked <0x00007f9aa457e400> (a sun.security.provider.SecureRandom)
    at sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:257)
    - locked <0x00007f9aa457e708> (a java.lang.Object)
    at sun.security.provider.NativePRNG$RandomIO.access$200(NativePRNG.java:108)
    at sun.security.provider.NativePRNG.engineNextBytes(NativePRNG.java:97)
    at java.security.SecureRandom.nextBytes(SecureRandom.java:433)
    - locked <0x00007f9aa4582fc8> (a java.security.SecureRandom)
    at java.util.UUID.randomUUID(UUID.java:162)
    at HeavyThread.run(HeavyThread.java:27)
    at java.lang.Thread.run(Thread.java:619)

そのため、クラスを実行しているスレッドHeavyThreadが最も多くの CPU を消費していることを確認できます。

読み取り世界の状況では、CPU の一部を消費するのはおそらく一連のスレッドであり、これらのスレッドをまとめると、Java プロセスが 100% CPU を使用することになります。

概要

  • ラントップ
  • Shift-H を押してスレッド ビューを有効にします
  • 最高の CPU を持つスレッドの PID を取得します
  • PID を HEX に変換する
  • Java プロセスのスタック ダンプを取得する
  • 一致する HEX PID を持つスレッドを探します。
于 2015-03-19T15:23:02.860 に答える
21

jvmtopは、最も多く消費しているスレッドを表示できます。

    TID NAME                                 STATE     CPU    TOTALCPU
     25 http-8080-Processor13                RUNNABLE  4.55%     1.60%
 128022 RMI TCP Connection(18)-10.101.       RUNNABLE  1.82%     0.02%
  36578 http-8080-Processor164               RUNNABLE  0.91%     2.35%
 128026 JMX server connection timeout   TIMED_WAITING  0.00%     0.00%
于 2013-03-26T14:42:47.530 に答える
19

ビジュアル VM 用の Hot Thread Detector プラグインを調べてみてください。ThreadMXBean API を使用して複数の CPU 消費サンプルを取得し、最もアクティブなスレッドを見つけます。これは、Bruce Chapman の同等のコマンドラインに基づいており、 これも役立つ可能性があります。

于 2009-05-31T01:58:59.027 に答える
11

JVisualVM を起動し、アプリに接続して、スレッド ビューを使用するだけです。継続的に活動しているものは、あなたの最も可能性の高い犯人です.

于 2009-05-31T01:33:12.293 に答える
6

JConsoleのTop Threadsプラグインを見てください。

于 2009-05-31T21:51:48.163 に答える
2

Windows で実行している場合は、Process Explorerを試してください。プロセスのプロパティ ダイアログを表示し、[スレッド] タブを選択します。

于 2009-05-31T01:36:43.317 に答える
1

スレッド ダンプを取得します。10 秒間待ちます。別のスレッド ダンプを取ります。もう一度繰り返します。スレッド ダンプを調べて、どのスレッドが同じ場所でスタックしているか、同じ要求を処理しているかを確認します。これは手動で行う方法ですが、多くの場合便利です。

于 2009-05-31T04:53:14.927 に答える
0

考慮できるオプションは、アプリケーション内からの回答をスレッドに照会することです。ThreadMXBeanを介して、Java アプリケーション内からスレッドの CPU 使用率を照会し、問題のあるスレッドのスタック トレースを照会できます。

ThreadMXBean オプションを使用すると、この種の監視をライブ アプリケーションに組み込むことができます。影響はほとんどなく、まさに自分のやりたいことを実行できるという明確な利点があります。

于 2009-05-31T05:20:22.867 に答える
0

これは一種のハックな方法ですが、デバッガーでアプリケーションを起動し、すべてのスレッドを一時停止して、コードを調べて、ロックまたは I/ でブロックされていないスレッドを見つけることができるようです。 O はある種のループを呼び出します。それとも、これはあなたがすでに試したことのようなものですか?

于 2009-05-31T01:05:28.853 に答える
0

VisualVM が優れたツールであると思われる場合は、それを試してください (これを行うため)。スレッドを見つけることは、CPU が大量に消費される理由の一般的な方向性に役立つだけです。

ただし、それが明らかな場合は、プロファイラーを使用して、CPU を大量に消費している理由を突き止めます。

于 2009-05-31T06:07:18.023 に答える