본문 바로가기
우아한 코딩

스레드 덤프 분석 실제 사례

by 피크인사이트 2024. 2. 29.
반응형

스레드 덤프(Thread Dump)는 JVM 내에서 실행 중인 모든 스레드의 상태 및 정보를 스냅샷으로 캡처한 것으로, 애플리케이션 문제 해결을 위해  상태를 분석할 수 있습니다.

아래는 스레드 덤프 예시와 문제 분석 과정 및 해결 방안에 대한 상세 설명입니다.

스레드 덤프 분석 실제 사례


1. 스레드 덤프 예시

스레드 덤프를 생성하여 문제를 분석하고 해결하기 위해 간단한 예시 코드를 작성해보겠습니다.

다음은 무한 루프를 포함한 스레드 예시 코드입니다.

public class ThreadDumpExample {
    public static void main(String[] args) {
        //...
        Thread thread = new Thread(() -> {
            while (true) {
                // 무한 루프
            }
        });
        thread.start();

        // 일정시간 대기 한후 스레드덤프 생성
        try {
            Thread.sleep(7000); // 7초 대기
            System.out.println("Generating thread dump...");
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
            for (ThreadInfo threadInfo : threadInfos) {
                System.out.println(threadInfo);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 이 예시 코드는 무한 루프를 포함한 스레드를 생성하고, 5초 후에 스레드 덤프를 생성하여 출력합니다.

 

다음은 이 코드를 실행하고 스레드 덤프를 확인해보겠습니다.


2. 문제 분석 과정

 코드에서 생성된 스레드 덤프는 스레드 정보를 포함하고 있습니다.

이를 통해 각 스레드의 상태와 실행 위치 등을 확인할 수 있습니다.

스레드 덤프는 실제로 매우 긴 정보를 포함하고 있어 모두 표시할 수는 없지만, 설명을 위해 예시로, 각 스레드의 스택 트레이스 정보 중 일부를 표시해 보겠습니다.

"Thread-0" #16 prio=5 os_prio=0 tid=0x00007fdd2c00d800 nid=0x3903 runnable [0x00007fdd2a2ff000]
   java.lang.Thread.State: RUNNABLE
	at ThreadDumpExample.lambda$main$0(ThreadDumpExample.java:7)
	at ThreadDumpExample$$Lambda$1/2105146201.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)


"main" #1 prio=5 os_prio=0 tid=0x00007fdd2c003000 nid=0x3900 waiting on condition [0x00007fdd304b7000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at ThreadDumpExample.main(ThreadDumpExample.java:18)

 

위 예시에서 스택 트레이스 정보를 보면 스레드 "Thread-0"은 무한 루프 내에서 실행되고 있습니다.

따라서 이 스레드는 RUNNABLE 상태로 계속해서 실행되고 있으며, 이는 프로그램이 원하는 동작과는 다르게 작동하고 있다는 것을 의미합니다.

또한, "main" 스레드는 TIMED_WAITING 상태로, sleep 메서드를 통해 일정 시간을 대기하고 있습니다.

이러한 상태는 프로그램이 멈춰있는 것처럼 보이지만 실제로는 대기하고 있는 상태를 나타냅니다.

이것으로 보아, "main" 스레드가 "Thread-0" 스레드의 작업이 완료될 때까지 대기하고 있음을 추측할 수 있습니다.

따라서 프로그램의 무한 루프와 "main" 스레드의 대기 상태가 예상치 못한 문제를 일으킬 가능성을 추측할 수 있습니다.


3. 문제 해결 방안

앞서 언급한 문제는 무한 루프가 발생하는 스레드와 메인 스레드가 대기 상태에 있는 것입니다.

이 문제를 해결하기 위해 무한 루프를 종료하고, 메인 스레드가 스레드 종료를 기다리지 않고 프로그램이 종료되도록 수정해야 합니다.

public class ThreadFix {
    private static int count = 0; //초기값
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                count++; 
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        });

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count: " + count);
    }
}

 

 이 코드에서는 무한 루프를 사용하지 않으며, 메인 스레드가 생성한 두 개의 스레드가 작업을 마칠 때까지 기다린 후에 결과를 출력합니다.

이렇게 수정된 코드는 무한 루프와 메인 스레드의 대기 상태 문제를 해결하여 예기치 않은 동작을 방지합니다.


4. 결론

지금까지 예제코드를 통해 스레드 덤프를 생성하고 분석하는 절차를 살펴보았습니다.

추가적으로 효과적인 스레드 덤프 분석을 위해 몇 가지 팁을 제공하자면,

첫 번째, 적절한 시점에 스레드 덤프를 생성하는 것이 중요합니다.

애플리케이션이 비정상적으로 동작하는 경우나 성능 문제가 발생한 경우에 스레드 덤프를 수집하면 됩니다.

두 번째, 스레드 덤프를 분석할 때는 각 스레드의 상태와 스택 트레이스를 주의 깊게 살펴보는 것도 중요합니다.

스레드의 상태와 스택 트레이스를 통해 어떤 스레드가 어떤 작업을 진행하고 있는지 파악할 수 있습니다.

또한 스레드 덤프로 스레드 간의 상호작용이나 데드락 등의 문제를 식별할 수 있습니다.

 

효과적인 스레드 덤프 분석에 도움이 되었길 기대하며 다음번엔 더 유용한 정보로 돌아오겠습니다. 

반응형