카테고리 없음

MAT(Memory Analyzer Tool) 로 OOM 분석

ssseung 2023. 3. 13. 15:08

문제 발생 

320만 건(약 2.5GiB)의 데이터를 8GB 서버에서 처리 중 OOM 발생

 

원인 파악

1.  jconsole로 확인했을 때 Heap 메모리는 충분했음

used: 현재 JVM이 사용 중인 Heap 메모리 (약 654MB)
committed: JVM이 OS로부터 확보한 Heap 메모리 (약 1GB)
max: JVM이 사용할 수 있는 최대 Heap 크기 (약 5GB)

 

2. jstat으로 GC 모니터링 → Survivor 영역(S0, S1)의 사용률이 비정상적(한쪽은 0%, 한쪽은 100%)

jstat 으로 2초 마다 GC 정보 확인 

- 데이터가 어느정도 로드된 후에는 GCT 가 점점 늘어난다.

- S0 , S1 은 Survivor 영역인데 S0은 0, S1은 계속 100프로로 고정되어 나온다.

* Minor GC가 발생할 때 Eden 에 있는 obj 들이 S0 혹은 S1 로 이동하고,

* Minor GC가 발생하면 S0 -> S1 혹은 S1 -> S0 으로 데이터가 옮겨지며 obj 의 age가 늘어나고, 한쪽은 완전히 비워진다.

* Meta 도 꽤 높이 차지하고 있다. 98-9% 였다가 MaxDirect 를 늘려주니까 96으로 아주 조금 떨어진 것 같다.

jstat -gccapacity -h20 -t [pid] 2000

 

3. top 명령어로 시스템 메모리 사용량 확인

- 메모리 사용량 확인 : used 3,225,240  free   1,305,580

top

 

4. Heap Dump 생성 후 MAT(Memory Analyzer Tool) 로 분석 

OOM 을 heapDump 로 떠서 MAT 로 분석.

결론 : ResultSet 쪽에서 발생하는 오류 , ResultSet이 1.9GB의 메모리를 점유

heapdump 생성 옵션

- 문제 코드

ResultSet rs = loadStmt.executeQuery(loadQuery);

 

MAT 화면

 

details >> 를 누르면 

 

여기서 object 를 클릭하면 List ojbects > outgoing references 를 누르면 아래와 같은 list_objects 를 볼 수 있다.

retained Heap 에 2,115,608,792 를 1,024로 세 번 나누면 1.9 GB 이다.

Xmx를 1gb 늘려보고  Xms 를 Xmx 와  동일하게 늘렸다.

그리고 gc발생 시 이그나이트에서 connection time out 이 발생해 timeout 설정 시간을 늘렸더니 해결됨.

 

 

문제 원인

  • JDBC ResultSet을 한꺼번에 메모리에 올려놓고 사용하여 메모리 부족 현상 발생
    -> JDBC ResultSet을 한꺼번에 메모리에 올려놓으면, Heap이 아닌 Native Memory(Direct Buffer, Metaspace 등) 를 과다 사용하여 OOM이 발생할 수 있음
  • GC 발생 후 Ignite에서 Connection Timeout이 발생하는 문제도 함께 확인됨
  • Meta 영역 사용량도 높은 상태

해결 과정

  1. Xmx(최대 Heap) 값을 1GB 늘리고, Xms(초기 Heap)도 Xmx와 동일하게 설정
    • 즉, -Xms와 -Xmx를 같은 값으로 설정해 Heap 크기를 고정하여 GC 오버헤드를 줄임
  2. Ignite의 Connection Timeout을 늘려서 GC 중에도 안정적인 연결 유지

결론

  • 결국 ResultSet을 과도하게 메모리에 로드하는 것이 문제였고, Heap 크기 조정 + Timeout 설정 변경으로 해결됨

 

 

 

 

 

반응형