Spring Boot · 2026-02-27

Spring Boot 메모리 누수 진단과 해결법

Spring Boot 애플리케이션에서 발생하는 메모리 누수를 단계별로 진단·분석하고 heap dump 분석·GC 로그 확인·코드 수정 등 주요 도구와 방법을 사례 중심으로 정리

작성일 : 2026-02-27 ㆍ 작성자 : 관리자
post
목차

개요

메모리 사용량이 점점 커지다가 결국 OOM(OutOfMemoryError)으로 종료되는 문제는 서비스 안정성에 큰 영향을 준다. 이 글에서는 spring boot 메모리 누수 찾기 를 위한 기초 개념과 실무 절차를 정리한다. 초보자도 따라올 수 있도록 진단 순서와 대표적인 원인, 해결법을 예제와 함께 설명한다.

증상 확인

먼저 증상을 정확히 확인한다. 메모리 누수는 다음과 같은 형태로 나타난다.

  • 애플리케이션 메모리 사용량이 지속적으로 증가
  • GC가 자주 발생하지만 메모리 회복이 미미
  • 서버 부하 증가와 응답 지연
  • 최종적으로 OutOfMemoryError 발생

운영 환경에서는 GC 로그와 프로세스 메모리 지표부터 수집한다.

진단 준비

진단을 위해 다음 도구를 준비한다.

  • jcmd, jmap, jstat (JDK 기본 도구)
  • VisualVM 또는 YourKit, JProfiler 같은 프로파일러
  • Eclipse Memory Analyzer (MAT)로 heap dump 분석

진단 절차

1) 프로세스 확인 및 GC 로그 확보

먼저 프로세스 ID를 확인하고 GC 로그를 활성화한다. 운영 중이라면 jcmd로 간단하게 요청해 GC 정보를 얻는다.

jcmd <pid> GC.run
jstat -gc <pid> 1000 10

2) 힙 덤프 수집

OOM 발생 전후로 힙 덤프를 확보한다. jmap을 사용하거나 jcmd로 요청한다. 덤프 파일은 MAT에서 분석한다.

jmap -dump:live,format=b,file=heap.hprof <pid>
# 또는
jcmd <pid> GC.heap_dump heap.hprof

3) 힙 덤프 분석 (heap dump 분석 spring boot)

MAT를 열고 heap.hprof를 로드한다. 주요 분석 포인트는 다음과 같다.

  • Dominator Tree로 큰 객체 그룹 찾기
  • Top Consumers로 메모리 사용 큰 클래스 확인
  • Leak Suspects 리포트로 잠재적 누수 경로 탐색

예를 들어 많은 메모리를 차지하는 객체가 static 컬렉션이나 ThreadLocal이면 누수 가능성이 높다.

대표적 원인과 해결법

1) Static 컬렉션에 누적

싱글톤 빈 또는 static 필드에 컬렉션을 두고 제거하지 않으면 메모리가 계속 쌓인다. 아래 코드는 문제가 되는 예와 수정 예이다.

// 문제 예시
public class LeakHolder {
    private static List<Object> cache = new ArrayList<>();
    public static void add(Object o) {
        cache.add(o);
    }
}

// 해결 예시
public class LeakHolderFixed {
    private static final int MAX = 1000;
    private static Deque<Object> cache = new ArrayDeque<>();
    public static synchronized void add(Object o) {
        cache.addLast(o);
        if (cache.size() > MAX) {
            cache.removeFirst();
        }
    }
}

2) ThreadLocal 미해제

웹 애플리케이션에서 ThreadLocal을 사용하면 스레드 풀의 스레드가 재사용될 때 의도치 않은 참조가 남을 수 있다. 작업이 끝난 후 반드시 remove()를 호출한다.

3) 캐시 설계 오류

캐시에 TTL이나 최대 크기 제한을 두지 않으면 메모리가 무한히 증가한다. Caffeine이나 Guava Cache 같은 검증된 라이브러리를 사용해 eviction 정책을 적용한다.

4) 리스너/콜백 미해제

등록한 리스너를 제거하지 않으면 참조가 남아 객체가 회수되지 않는다. 등록-해제 라이프사이클을 명확히 관리한다.

5) 외부 리소스 미반납

JDBC 커넥션, InputStream 같은 리소스가 닫히지 않으면 누수가 발생한다. try-with-resources 패턴을 사용하면 안전하다.

try (InputStream in = resource.openStream()) {
    // 처리
}

실전 검증 방법

문제 수정 후에는 재현 테스트와 장기간 부하 테스트로 검증한다. 다음 절차를 권장한다.

  • 수정 전/후 힙 덤프 비교
  • GC 로그와 메트릭을 장시간 수집
  • 프로파일러로 객체 생성 패턴 확인

유용한 명령 모음

# 프로세스 확인
jps -l

# 힙 덤프 생성
jmap -dump:live,format=b,file=heap.hprof <pid>

# GC 강제 실행
jcmd <pid> GC.run

# GC 상태 확인
jstat -gc <pid> 1000

정리

memory leak spring boot 해결 을 위해서는 증상 파악, 힙 덤프 확보, MAT 등의 도구로 분석, 코드 개선과 검증의 순서가 중요하다. 특히 spring boot 메모리 누수 찾기 에서는 운영 환경의 로그와 메트릭이 중요한 단서가 된다. 도구를 익히고 반복적으로 검증하면 안정성을 크게 개선할 수 있다.

spring boot 메모리 누수 찾기 heap dump 분석 spring boot memory leak spring boot 해결 Spring Boot 메모리 누수 진단 Eclipse MAT jmap jcmd GC 분석