Java 프로세스(JVM)가 고부하 상태일 때, CPU를 점유하고 있는 범인(특정 스레드)을 찾아내는 방법을 정리합니다. OS 명령어(ps, top)로 문제의 스레드 ID(TID)를 식별하고, 이를 16진수로 변환하여 Java Thread Dump와 매핑하는 과정을 다룹니다.
Test Environment
- OS: RedHat Linux (CentOS 호환)
- Target: Java Process (WebSphere/Tomcat 등)
1. 프로세스 및 스레드 식별 (Identify Usage)
먼저 CPU를 많이 사용하는 Java 프로세스의 PID(Process ID)를 찾고, 그 내부에서 실제로 리소스를 소모하는 스레드(LWP, Light Weight Process)를 식별해야 합니다.
전체 프로세스 확인
# Java 프로세스 PID 확인
ps -ef | grep java
스레드별 CPU 점유율 확인 (top)
-H 옵션을 사용하여 프로세스 내부의 스레드 단위로 리소스를 모니터링합니다.
# PID가 12345인 경우
top -H -p 12345
출력 화면에서 PID(실제로는 TID/LWP) 컬럼과 %CPU 컬럼을 확인하여 가장 상단에 있는 번호를 기록합니다.
스레드별 CPU 점유율 확인 (ps)
ps 명령어를 통해서도 스레드 정보를 확인할 수 있습니다. -lmT 옵션이나 -L 옵션을 사용합니다.
# LWP(Light Weight Process) 확인
ps -lmT [PID]
# 또는 커스텀 포맷 사용
ps -eLo pid,lwp,pcpu,comm | grep [PID]
2. 스레드 ID 변환 (Decimal to Hex)
OS에서 확인한 스레드 ID는 10진수(Decimal)이지만, Java Thread Dump 파일(Javacore 등)에서는 스레드 ID가 16진수(Hexadecimal)로 기록됩니다. 따라서 매핑을 위해 변환 과정이 필요합니다.
변환 예시
- OS TID: 9091 (10진수)
- Hex TID: 0x2383 (16진수)
변환 명령어
# 쉘에서 바로 변환하기 (예: 9091 -> 2383)
printf '%x\n' 9091
3. 스레드 덤프 생성 및 분석 (Thread Dump)
현재 JVM의 상태를 스냅샷으로 남기기 위해 스레드 덤프를 생성합니다.
덤프 생성 (Kill -3)
kill -3 시그널은 프로세스를 종료하지 않고 표준 출력(stdout)이나 로그 파일로 스레드 정보를 출력합니다.
kill -3 [PID]
- IBM JDK (WebSphere):
javacore.YYYYMMDD.HHMMSS.pid.txt파일 생성 - Oracle/Open JDK:
catalina.out또는 지정된 로그 파일에 출력
로그 매핑 분석
생성된 덤프 파일에서 앞서 변환한 16진수 값(예: 0x2383)을 검색합니다. IBM JDK의 경우 nid(Native ID) 또는 native_thread_id 항목과 매칭됩니다.
/* Javacore 예시 */
"WebContainer : 5" (TID:0x12345600, sys_thread_t:0x789abc00, state:R, native ID:0x2383) prio=5
at com.example.MyClass.infiniteLoop(MyClass.java:45)
at ...
분석 포인트:
- 16진수 ID로 검색하여 해당 스레드를 찾습니다.
- 해당 스레드의 상태(Runnable, Waiting 등)를 확인합니다.
- Stack Trace를 통해 현재 어떤 코드(메소드)가 실행 중인지 파악하여 병목 지점을 수정합니다.
Next Step:
주기적인 모니터링이 필요하다면 top -H와 jstack을 결합한 쉘 스크립트를 작성하여, CPU 임계치 초과 시 자동으로 덤프를 남기도록 자동화해 보십시오.