H7. 메모리 누수 의심 시 점검 (힙·GC·힙덤프)
Diátaxis: How-to(목표별 가이드) · 대상: 운영자 / 관리자 ← 목차로
"시간이 지날수록 응답이 느려지다 가끔 멈춘다", "재시작하면 한동안 괜찮다"는 증상은 메모리 누수의 전형입니다. 이 문서는 WAS의 JVM 탭 차트로 누수를 가려내고, 의심되면 힙 오브젝트 분석까지 파고드는 순서를 정리합니다.
"힙·GC가 무엇인가"라는 개념은 E3.2 JVM 건강을, 차트별 정확한 임계치는 R2.1 WAS 차트 — JVM을 보세요. 대상 인스턴스를 고르는 법은 H1. 모니터링 대상 좁히기에 있습니다.
여는 법 — 좌측 메뉴 ▸ WAS ▸ (인스턴스 선택) ▸ JVM 탭

힙 사용률 패턴 읽기 (톱니 vs 평탄)
가장 먼저 JVM 힙 사용률(%) 차트의 모양을 봅니다. 절대값보다 모양이 먼저입니다.
| 모양 | 해석 |
|---|---|
| 톱니(▴▾▴▾) — 올랐다가 GC 후 뚝 떨어짐이 반복 | 정상 — 청소가 제대로 되고 있음 |
| 계단식으로 바닥이 점점 높아짐 | 주의 — 누수 의심. GC를 해도 회수되지 않는 객체가 쌓이는 중 |
| 80% 이상에서 평탄 (거의 안 내려감) | 위험 — 누수 진행 가능성 높음. 곧 OutOfMemoryError 위험 |

참고 짧은 구간만 보면 판단이 어렵습니다. H2. 기간 바꿔 보기로 최근 1일~1주 구간을 펼쳐, "바닥선(GC 직후 최저점)이 우상향하는가"를 확인하세요. 바닥선이 계속 올라가면 누수입니다.
이어 JVM 메모리 크기 차트에서 Used가 Max에 근접하는지 봅니다. Used 선이 Max 선에 달라붙으면 여유가 없는 상태입니다.

위 화면이 누수가 진행 중인 모양입니다. 위 정상 차트와 비교해 보세요 — 톱니는 톱니인데
GC 직후 최저점(바닥)이 매번 더 높아지 고, GC가 회수하는 양(낙폭)은 점점 줄다가, 끝내
사용 중인 힙이 메모리 크기(Max) 선에 붙은 채 평탄해집니다. 이 상태가 곧
OutOfMemoryError 직전입니다.
GC 시간·횟수 확인
누수가 진행되면 JVM은 메모리를 짜내려고 GC를 더 자주, 더 오래 돌립니다. GC 시간 차트에서 두 가지를 봅니다.
- GC 횟수가 평소보다 잦아짐 — 회수할 공간이 부족해 청소를 반복
- 개별 GC 소요시간이 길어짐(예: 500ms 이상이 빈번) — 청소하는 동안 애플리케이션이 멈춰(Stop-the-World), 사용자가 지연·멈춤을 체감


두 화면을 비교하세요. 정상(위)은 GC가 일정한 주기로, 비슷한 크기로 돕니다. 누수(아래)는 시간이 갈수록 ① Young GC(초록) 간격이 좁아지고 ② 소요시간이 길어지며 ③ 후반부에는 Old(Full) GC(파랑)까지 등장해 1초를 넘깁니다 — 회수할 공간이 말라가면서 JVM이 점점 더 필사적으로 청소하는 모양입니다.
주의 "힙은 아직 여유 있는데 응답만 느리다"면 누수가 아니라 GC 튜닝/객체 생성 과다 문제일 수 있습니다. 이때는 힙 크기·GC 알고리즘 설정을 함께 점검합니다(R2.1 — GC 시간).
Full GC 버튼으로 누수 가려내기
힙이 점점 차오르는데 정말 누수인지, 아니면 아직 정리가 안 됐을 뿐인지 헷갈릴 때는 직접 한 번 청소시켜 보는 것이 가장 빠릅니다. JVM 탭 우측 상단의 Full GC 실행 버튼은 그 인스턴스에 전체(Full) GC를 강제로 한 번 돌립니다.
- 메모리 크기(또는 메모리 사용률) 차트를 띄워 둔 채, 우측 상단 Full GC 실행 버튼을 누릅니다.
- 버튼 직후 사용 중인 힙 선이 어떻게 움직이는지 봅니다.
| Full GC 직후 모습 | 해석 |
|---|---|
| 힙이 뚝 많이 떨어지고, 낮은 자리로 내려감 | 누수 아닐 가능성 높음 — 쌓인 건 회수 가능한 임시 객체였음. 정리가 늦었을 뿐 |
| 힙이 거의 안 내려가거나, 내려간 지점이 여전히 높은 자리에 머묾 | 누수 가능성 높음 — GC로도 못 비우는 객체가 그만큼 쌓여 있다는 뜻 |
핵심 누수의 정의가 바로 이것입니다 — "Full GC를 해도 회수되지 않는다." 한 번 더 확실히 하려면, 잠시 뒤 Full GC를 한 번 더 눌러 봅니다. 누를 때마다 내려간 바닥이 계속 높아진다면 누수가 진행 중입니다.
주의 Full GC는 그 순간 애플리케이션을 잠깐 멈춥니다(Stop-the-World). 트래픽이 적은 시간대에, 가능하면 한 인스턴스에만 눌러 확인하세요. 누수로 확정되면 다음 절에서 무엇이 쌓이는지를 봅니다.
힙 히스토그램·힙덤프 요청
차트로 "누수 같다"까지 좁혔으면, 무엇이 쌓이는지를 봅니다. JVM 탭의 분석 도구를 사용합니다.
- 힙 오브젝트 분석(Heap Object Analyze)을 실행합니다. 해당 인스턴스의 JVM 메모리 히스토그램을 수집해, 어떤 클래스의 인스턴스가 가장 많은 메모리를 차지하는지 목록으로 보여 줍니다.
- 시간차를 두고 두 번 수집해 비교하면 좋습니다 — 같은 클래스의 인스턴스 수·점유 메모리가 계속 늘어난다면 그 클래스가 누수 후보입니다.
- 필요하면 스레드 덤프 분석(Thread Dump Analyze)도 함께 받아, 특정 작업이 객체를 계속 붙잡고 있는지 확인합니다.

위 화면처럼 좌측 스냅샷 목록에서 요청으로 히스토그램을 수집하고, 수집된 스냅샷을 골라
분석을 누르면 우측에 클래스별 점유 메모리(바이트·%)와 인스턴스 수가 큰 순서로
나열됩니다. 두 스냅샷을 골라 차이 분석을 누르면 Bytes Diff · Instances Diff 컬럼으로
증가분만 비교할 수 있습니다.
참고 히스토그램과 덤프는 사용자 요청으로 즉시 수집할 수도 있고, OOM·데드락 같은 이벤트가 발생하면 자동 수집되기도 합니다. 자동 수집분은 이벤트 목록에서 해당 이벤트를 열어 확인할 수 있습니다(R3. 이벤트 종류 레퍼런스).
주의 힙덤프 수집은 그 순간 JVM을 멈출 수 있어 부하가 큽니다. 트래픽이 적은 시간대에, 가능하면 한 인스턴스에만 요청하세요.
조치
| 확인된 상황 | 1차 조치 |
|---|---|
| 누수 후보 클래스가 보임 | 해당 코드의 캐시·컬렉션·리스너 등록 해제 누락 점검 (개발팀 전달) |
| 당장 서비스가 위태로 움(힙 90%+, 잦은 풀 GC) | 트래픽 분산 후 해당 인스턴스 순차 재시작으로 우선 안정화 |
| Used가 Max에 자주 닿음(누수는 아님) | 힙 최대치(-Xmx) 상향 또는 메모리 사용 최적화 |
OutOfMemoryError 이미 발생 | 이벤트에 자동 저장된 힙 객체 분석 결과부터 확인 |
재시작은 증상 완화일 뿐 원인 해결이 아닙니다. 누수 후보를 함께 기록해 두어야 다음에 반복되지 않습니다.
잘 안될 때
| 증상 | 점검 |
|---|---|
| JVM 탭에 힙 데이터가 비어 있음 | 인스턴스가 연결돼 있는지(에이전트 상태) — H20. 에이전트 점검 |
| 힙 오브젝트 분석 버튼이 없음/안 눌림 | 해당 인스턴스가 살아 있고 분석을 지원하는지 확인 |
| 패턴이 톱니인데도 느림 | 누수가 아닐 수 있음 — H6. 느린 트랜잭션 원인 찾기로 전환 |
관련 문서
- E3.2 JVM 건강 — 힙·GC· 스레드 개념
- R2.1 WAS 차트 — JVM — 차트별 의미·임계치
- H6. 느린 트랜잭션 원인 찾기 — 누수가 아닐 때
- H14. AI로 차트·이벤트 분석 받기 — 힙 차트를 AI에게 바로 진단 요청