Programing

어떤 자바 스레드가 CPU를 차지하고 있습니까?

lottogame 2020. 12. 15. 08:10
반응형

어떤 자바 스레드가 CPU를 차지하고 있습니까?


Java 프로그램이 100 % CPU를 사용한다고 가정 해 보겠습니다. 50 개의 스레드가 있습니다. 어떤 스레드가 유죄인지 찾아야합니다. 도움이 될 수있는 도구를 찾지 못했습니다. 현재 나는 매우 시간이 많이 걸리는 다음 루틴을 사용합니다.

  1. Run jstack <pid>, 여기서 pid는 Java 프로세스의 프로세스 ID입니다. 쉽게 찾을 수있는 방법은 JDK에 포함 된 다른 유틸리티를 실행하는 것입니다 jps. jstack의 출력을 파일로 리디렉션하는 것이 좋습니다.
  2. "실행 가능"스레드를 검색하십시오. 소켓에서 대기하는 항목을 건너 뜁니다 (어떤 이유로 여전히 실행 가능으로 표시됨).
  3. 1 단계와 2 단계를 두 번 반복하고 패턴을 찾을 수 있는지 확인합니다.

또는 Eclipse에서 Java 프로세스에 연결하고 CPU를 소모하는 스레드에 도달 할 때까지 스레드를 하나씩 일시 중단 할 수 있습니다. CPU가 하나 인 컴퓨터에서는 먼저 Java 프로세스의 우선 순위를 줄여야 이동할 수 있습니다. 그럼에도 불구하고 Eclipse는 종종 시간 초과로 인해 실행중인 프로세스에 연결할 수 없습니다.

나는 Sun의 visualvm도구가 이것을 할 것이라고 기대했을 것 입니다.

아무도 더 나은 방법을 알고 있습니까?


Visual VM 용 Hot Thread Detector 플러그인을 살펴보세요 . ThreadMXBean API를 사용하여 여러 CPU 소비 샘플을 가져와 가장 활동적인 스레드를 찾습니다. 유용 할 수도있는 Bruce Chapman과 동등한 명령 줄을 기반 으로합니다.


프로덕션 서버에서 대부분의 CPU를 사용하는 Java 스레드 식별.

중요한 작업을 수행하는 대부분의 (전부는 아니지만) 생산적인 시스템은 하나 이상의 Java 스레드를 사용합니다. 그리고 뭔가 미쳐 가고 CPU 사용량이 100 %이면 어떤 스레드가이 문제를 일으키는 지 식별하기가 어렵습니다. 아니면 그렇게 생각했습니다. 나보다 똑똑한 사람이 어떻게 할 수 있는지 보여줄 때까지. 그리고 여기서 나는 그것을하는 방법을 보여줄 것이며 당신도 괴짜 기술로 가족과 친구들을 놀라게 할 수 있습니다.

테스트 애플리케이션

이를 테스트하려면 테스트 애플리케이션이 필요합니다. 그래서 하나 줄게. 3 개의 클래스로 구성됩니다.

  • HeavyThreadCPU 집약적 인 작업을 수행 하는 클래스 (MD5 해시 계산)
  • LightThreadCPU 집약적이지 않은 작업 (카운팅 및 수면)을 수행 하는 클래스입니다.
  • 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를 누르면 스레드가 켜집니다. top의 man 페이지는 다음과 같이 말합니다.

   -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.

이제 스레드 디스플레이가 켜져있는 맨 위에 다음이 표시됩니다. 스레드가 표시된 상단 스크린 샷

그리고 javaPID 프로세스가 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. 스택 덤프에서 각 스레드에는 nid16 진수로 표시되는가 있습니다. 그리고 그것은 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의 일부를 소비하는 스레드 묶음이 될 것이며 이러한 스레드를 함께 모으면 100 % CPU를 사용하는 Java 프로세스로 이어질 것입니다.

요약

  • 런 탑
  • 스레드보기를 활성화하려면 Shift-H를 누릅니다.
  • CPU가 가장 높은 스레드의 PID 가져 오기
  • PID를 HEX로 변환
  • Java 프로세스의 스택 덤프 가져 오기
  • HEX PID가 일치하는 스레드를 찾습니다.

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%

JVisualVM을 실행하고 앱에 연결 한 다음 스레드보기를 사용하면됩니다. 지속적으로 활동하는 것이 가장 큰 원인입니다.


JConsole 용 Top Threads 플러그인을 살펴보십시오 .


If you're running under Windows, try Process Explorer. Bring up the properties dialog for your process, then select the Threads tab.


Take a thread dump. Wait for 10 seconds. Take another thread dump. Repeat one more time. Inspect the thread dumps and see which threads are stuck at the same place, or processing the same request. This is a manual way of doing it, but often useful.


Are you running Java 6 on a multi-core computer?

Chances are that you are suffering from a problem I just described in an article about thread starvation.

See Synchronized vs. Lock vs. fair Lock.


I would recommend taking a look at Arthas tool open sourced by Alibaba.

It contains a bunch of useful commands that can help you debug your production code:

  • Dashboard: Overview of Your Java Process
  • SC: Search Class Loaded by Your JVM
  • Jad: Decompile Class Into Source Code
  • Watch: View Method Invocation Input and Results
  • Trace: Find the Bottleneck of Your Method Invocation
  • Monitor: View Method Invocation Statistics
  • Stack: View Call Stack of the Method
  • Tt: Time Tunnel of Method Invocations

Example of the dashboard: 계기반


This is a kind of hacky way, but it seems like you could fire the application up in a debugger, and then suspend all the threads, and go through the code and find out which one isn't blocking on a lock or an I/O call in some kind of loop. Or is this like what you've already tried?


An option you could consider is querying your threads for the answer from within application. Via the ThreadMXBean you can query CPU usage of threads from within your Java application and query stack traces of the offending thread(s).

The ThreadMXBean option allows you to build this kind of monitoring into your live application. It has negligible impact and has the distinct advantage that you can make it do exactly what you want.


If you suspect VisualVM is a good tool, try it (because it does this) Find out the threads(s) only helps you in the general direction of why it is consuming so much CPU.

However, if its that obvious I would go straight to using a profiler to find out why you are consuming so much CPU.

참조 URL : https://stackoverflow.com/questions/930915/which-java-thread-is-hogging-the-cpu

반응형