Java 프로세스의 상태를 진단하는 세 가지 핵심 도구

Java 프로세스가 느려지거나 메모리가 부족할 때(OutOfMemory) 이를 진단하는 세 가지 핵심 도구가 있습니다.

  1. Heap Dump (힙 덤프): 메모리 부족(OOM) 해결
    • “메모리의 스냅샷”으로 특정 시점에 Java 가상 머신(JVM) 메모리에 어떤 객체들이 들어 있는지 기록한 파일입니다. 어떤 객체가 메모리를 많이 차지하는지, 메모리 누수(Leak)가 어디서 발생하는지 찾을 때 사용합니다.
    • Java Options(jdk 버전별로 상이)
      • -XX:+HeapDumpOnOutOfMemoryError: (필수) OOM 발생 시 자동으로 힙 덤프를 생성합니다.
      • -XX:HeapDumpPath=/path/to/DUMP/: 덤프 파일이 저장될 경로를 지정합니다. (파일명까지 지정 가능)
        예: -XX:HeapDumpPath=/var/log/java/heapdump.hprof
      • -XX:OnOutOfMemoryError="<command>": OOM 발생 시 특정 스크립트나 명령어를 실행합니다. (예: 관리자에게 메일 발송, 프로세스 재시작 등)
    • 강제 생성 방법
      # jcmd 사용 (권장)
      jcmd <PID> GC.heap_dump /path/to/java_pid<PID>.hprof
      
      # jmap 사용
      jmap -dump:format=b,file=java_pid<PID>.hprof <PID>
      
    • 분석 방법: 파일 용량이 크기 때문에 전용 툴이 필요합니다.
      • Eclipse MAT(Memory Analyzer): 가장 강력하고 대중적인 무료 분석 도구입니다. “Eclipse MAT(Memory Analyzer) 사용법” 글을 참고해 주세요.
      • VisualVM: JDK에 포함된 기본 도구로 가볍게 보기 좋습니다.
  2. Thread Dump (스레드 덤프): CPU 과부하, 응답 저하 해결
    • “스레드가 현재 무엇을 하고 있는가?”를 보기 위해 모든 스레드의 상태(Running, Waiting, Blocked)와 현재 실행 중인 코드 라인을 텍스트로 기록한 것입니다. 서버가 응답이 없거나(Hang), 데드락(Deadlock)이 의심될 때 어떤 스레드가 범인인지 찾기 위해 사용합니다.
    • Java Options(jdk 버전별로 상이)
      • -XX:+PrintConcurrentLocks: jstack 등을 실행할 때 스레드가 소유한 락(Lock) 정보를 더 자세히 출력합니다. (데드락 분석 시 매우 유용)
      • -XX:ErrorFile=/path/to/logs/hs_err_pid%p.log: JVM이 치명적인 에러(Crash)로 종료될 때 생성되는 hs_err_pid<PID>.log 파일의 경로를 지정합니다. 이 파일 안에 종료 직전의 스레드 상태가 포함됩니다.
    • 강제 생성 방법
      # jstack 사용
      jstack <PID> > hs_err_pid<PID>.log
      
      # jhsdb 사용 (소켓 파일이 없어도 프로세스 메모리에 직접 접근)
      jhsdb jstack --pid <PID> > hs_err_pid<PID>.log
      
      # kill 신호 사용 (Java 프로세스가 실행될 때 연결된 stdout으로 출력 또는 저장됨)
      kill -3 <PID>
      
    • 분석 방법
  3. 프로세스 스택 (Process Stack / Native Stack): 저수준 병목 진단
    • “운영체제 레벨의 호출 기록”으로, Java 코드뿐만 아니라, JVM 자체나 C/C++로 작성된 Native 라이브러리가 운영체제 자원을 어떻게 쓰는지 보여줍니다. Java 레벨(jstack)에서 보이지 않는 OS 시스템 콜 지연이나, 커널 레벨의 병목을 진단할 때 사용합니다.
    • Java Options(jdk 버전별로 상이)
      • -verbose:gc / -Xlog:gc: 가장 기본적인 GC 로깅 옵션입니다. GC가 발생할 때마다 한 줄씩 로그를 남깁니다.
      • -Xloggc:/path/to/GC/gc.log: 가비지 컬렉션(GC) 로그를 파일로 저장합니다. (메모리 변화 추이를 볼 때 필수)
      • -XX:+PrintGCDetails / -Xlog:gc*: GC 로그에 상세 내역을 기록합니다.
        (사용법 -Xlog:gc*:file=/app/logs/gc.log:time,uptime,level,tags:filecount=5,filesize=10M)
      • -XX:+PrintGCTimeStamps: GC 로그에 JVM이 시작된 시점(0.000초)을 기준으로 소요된 시간을 초 단위로 기록합니다.
      • -XX:+PrintGCDateStamps / -Xlog:gc:time: 기본 GC 로그는 서버가 켜진 지 몇 초 지났는지(Relative time)만 표시하는데, 이를 절대 시간(Calendar time)으로 바꿔줍니다.
      • -XX:+PrintHeapAtGC: 가장 상세한 옵션 중 하나로, GC가 일어나기 직전과 직후에 각 영역(Young, Old, Metaspace 등)의 상세 상태를 전부 출력합니다.
      • -XX:+ExitOnOutOfMemoryError: (복구 위주)OOM 발생 시 덤프만 남기고 프로세스가 좀비 상태로 남는 것을 방지하기 위해 즉시 종료시킵니다.(컨테이너 환경에서 유용)
      • -XX:+CrashOnOutOfMemoryError: (분석 위주)OOM 발생 시 프로세스를 종료하면서 -XX:ErrorFile 옵션에 설정된 hs_err_pid<PID>.log 파일을 생성합니다. 이 파일 안에는 Thread Dump, 프로세스 스택(Native Stack), OS 메모리 상태 등이 텍스트로 상세히 기록됩니다. 즉, 단순히 죽이기만 하려면 Exit, 기록을 남기며 죽이려면 Crash 옵션을 사용합니다.
    • 강제 생성 방법:
      # pstack 사용 (리눅스 표준)
      pstack <PID> > pstack_pid<PID>.txt
      
      # gdb 사용
      gdb -batch -ex "thread apply all bt" -p <PID> > gstack_pid<PID>.txt
      
    • 분석 방법: 주로 시스템 엔지니어가 C 함수 호출 흐름을 파악하는 데 사용하며, 텍스트 분석 위주입니다.

You may also like...

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다