반응형

기본 Xms Xmx

 java -jar -Dspring.profiles.active=real xxx.jar

로 실행하고 있는 프로세스가 있다. 띄울 때 최소/최대 힙 사이즈를 안 줘서 기본값으로 어떻게 들고 있는지 궁금했다.

java -XX:+PrintFlagsFinal -version | grep -E "InitialHeapSize|MaxHeapSize"
   size_t InitialHeapSize                          = 62914560      
   size_t MaxHeapSize                              = 994050048

위 명령어를 사용하면 현재 JVM의 기본 힙 설정을 알 수 있다.

각각은 바이트 단위이다. 따라서 좀 더 이해하기 쉽게 바꿔보면

  1. 바이트(Byte) -> 킬로바이트(Kilobyte):
    • 1KB = 1024B
    • 62914560 ÷ 1024 = 61440 KB
  2. 킬로바이트(Kilobyte) -> 메가바이트(Megabyte):
    • 1MB = 1024KB
    • 61440 ÷ 1024 = 60 MB

따라서, initialHeapSize가 62914560이라는 값은 60MB를 잡고 있다는 뜻이다.

또한 최대 값을 계산해보면

  1. 바이트(Byte) -> 킬로바이트(Kilobyte):
    • 1KB = 1024B
    • 994050048 ÷ 1024 = 970752 KB
  2. 킬로바이트(Kilobyte) -> 메가바이트(Megabyte):
    • 1MB = 1024KB
    • 970752 ÷ 1024 = 948 MB

따라서, maxHeapSize가 994050048 바이트라는 값은 약 948MB를 최대 값으로 설정했다는 것이다.

 

지금 메모리 현황 보기

free -h

              total        used        free      shared  buff/cache   available
Mem:           3.7G        933M        976M        137M        1.8G        2.3G
Swap:          2.0G         13M        2.0G

 

gc 관련 모니터링(jstat) 권한없어도 가능

jstat -gc <PID> <interval> <count>
jstat -gc 12345 1000 10  # 12345 PID의 JVM에 대해 1초 간격으로 10번 GC 정보를 출력

//
S0C    S1C    S0U    S1U      EC       EU        OC        OU      MC       MU     CCSC     CCSU       YGC    FGC
1024.0 1024.0   0.0   0.0   8192.0   1024.0   20480.0    8192.0    512.0    488.0   64.0     62.0       3      1
  • S0C/S1C: Survivor space 0/1의 용량.
  • EC: Eden 영역의 용량.
  • OC: Old 영역의 용량.
  • YGC/FGC: Young/Full GC의 발생 횟수.

 

OOM이 터질 때 자동으로 덤프를 뜨게 하는 옵션을 주려면 아래와 같은 옵션을 자바에 추가한다.

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/경로/heapdump.hprof

 

이미 뭔가 데드락이나 무한루프에 빠진 것 같다면 확인하기

각 스레드의 상태현재 실행 중인 코드를 볼 수 있음(권한 필요)

jstack <PID>
"main" #1 prio=5 os_prio=0 tid=0x00000000023f6000 nid=0x2c runnable [0x0000000002a1e000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.Thread.sleep(Native Method)
        at Example.main(Example.java:5)

 

현재 돌고 있는 프로세스의 덤프 뜨는 법

jmap이나 jcmd 명령어 사용(권한 필요)

sudo jmap -dump:format=b,file=/경로/heapdump.hprof <PID>
-- or 
jcmd <PID> GC.heap_dump <경로>


// /proc/3272/root폴더에 권한이 없을 경우
Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file /proc/3272/root/tmp/.java_pid3272: target process 3272 doesn't respond within 10500ms or HotSpot VM not loaded
        at jdk.attach/sun.tools.attach.VirtualMachineImpl.<init>(VirtualMachineImpl.java:100)
        at jdk.attach/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:58)
        at jdk.attach/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:207)
        at jdk.jcmd/sun.tools.jmap.JMap.executeCommandForPid(JMap.java:128)
        at jdk.jcmd/sun.tools.jmap.JMap.dump(JMap.java:208)
        at jdk.jcmd/sun.tools.jmap.JMap.main(JMap.java:114)

 

MAT(Eclipse Memory Analyzer Tool)

hprof파일을 얻었으면 분석 프로그램인 eclipse MAT 프로그램이 필요하다.

다운로드하고 hprof파일을 열어준다. hprof 파일의 용량이 클 수록 오래걸린다.

 

분석 보고서 이해하기

  • Overview (개요): 메모리 상태, 누수 가능성, 가장 큰 객체 등을 요약하여 보여줌
  • Dominator Tree: 힙 메모리의 최상위 점유자를 트리 구조로 보여주며 메모리 점유 비율이 큰 객체를 쉽게 파악 가능
  • Histogram: 클래스별로 객체 수와 메모리 점유량
  • Top Consumers: 메모리 사용량이 큰 객체 그룹

힙 분석 예시

  1. 메모리 누수 확인:
    • Leak Suspects Report를 사용하면 누수 가능성이 있는 객체를 분석하여 보여줌
    • "Path to GC Root" 기능을 사용해 메모리에서 해제되지 않은 객체의 참조 경로를 추적할 수 있음
  2. Dominator Tree 분석:
    • Dominator Tree를 통해 메모리를 가장 많이 차지하는 객체 파악
    • with outgoing references를 사용하여 참조 중인 객체들을 확인
  3. Histogram 분석:
    • 클래스별로 객체 수와 메모리 점유율을 확인하여 특정 클래스가 메모리를 많이 사용하는지 파악
    • 특정 클래스에서 메모리를 많이 사용하는 객체가 있다면, 이를 "List Objects -> with incoming references"로 추적 가능

 

728x90
반응형

+ Recent posts