튼튼발자 개발 성장기🏋️

자바 static 메모리 구조와 GC 대상 여부: 실전 가이드 본문

프로그래밍/JAVA

자바 static 메모리 구조와 GC 대상 여부: 실전 가이드

시뻘건 튼튼발자 2025. 5. 27. 10:57
반응형
  1. JVM 메모리 구조의 기본 이해
  2. static 변수와 GC 대상의 차이
  3. 톰캣 환경에서 static 변수 누수가 생기는 이유
  4. 오토박싱과 리터럴의 메모리 저장 위치
  5. static 변수 사용 시 메모리 누수 방지 전략

1. JVM 메모리 구조의 기본 이해

1-1. 메서드 영역, 힙, 스택은 어떻게 다를까?

자바 애플리케이션이 실행되면 JVM은 메모리를 여러 영역으로 나누어 데이터를 저장합니다. 가장 대표적인 세 가지는 메서드 영역(Metaspace), 힙 영역(Heap), 그리고 스택(Stack)입니다.

  • 메서드 영역: 클래스 정보, static 변수, 런타임 상수 풀
  • 힙: new로 생성된 객체 및 인스턴스 변수 저장. GC 대상
  • 스택: 지역 변수 저장, 메서드 종료 시 자동 소멸

1-2. static 변수와 메서드 영역의 관계

static 변수는 클래스 로딩 시 메서드 영역에 저장되며, 인스턴스가 없어도 접근이 가능합니다. 이들은 GC의 일반 대상이 아니며, 해당 클래스가 언로드되기 전까지 메모리에 남습니다.

2. static 변수와 GC 대상의 차이

2-1. static 변수는 GC 대상이 아닌가?

static 변수는 메서드 영역에 존재하기 때문에 GC 대상이 아닙니다. 하지만 static 변수가 new 객체를 참조하고 있다면, 해당 객체도 GC 대상에서 제외되어 메모리 누수가 발생할 수 있습니다.

2-2. new 연산자와 GC 참조 여부

new 연산자로 생성된 객체는 일반적으로 GC 대상이지만, static이 참조하는 경우엔 예외입니다. 즉, 객체 생성이 아니라 참조 여부가 GC의 핵심 조건입니다.

3. 톰캣 환경에서 static 변수 누수가 생기는 이유

3-1. 클래스 언로드 실패와 메모리 점유

톰캣은 웹앱마다 ClassLoader를 따로 갖습니다. 이 ClassLoader가 언로드되지 않으면 static 변수도 남게 되어 메모리 누수가 생깁니다. 특히 hot redeploy 시 문제 발생 가능성이 큽니다.

3-2. 실무 사례로 보는 메모리 누수

static 리스트에 데이터를 쌓는 REST API는 요청이 반복될수록 객체가 메모리에 남아 OutOfMemoryError를 일으킬 수 있습니다.

4. 오토박싱과 리터럴의 메모리 저장 위치

4-1. 오토박싱된 객체는 어디 저장될까?

오토박싱은 기본형 데이터를 래퍼 객체로 자동 변환합니다. Integer.valueOf() 방식으로 캐싱 범위 내에 있는 값은 GC 대상이 아닙니다.

4-2. 캐싱 범위와 힙 객체 생성의 차이

  • Integer.valueOf(10): 캐시 범위 (-128~127)이면 GC 대상 아님
  • new Integer(10): 무조건 힙 객체, GC 대상

5. static 변수 사용 시 메모리 누수 방지 전략

5-1. 약한 참조의 활용(WeakReference)

WeakReference, WeakHashMap 등은 GC가 객체를 수거할 수 있도록 도와줍니다. 예시:

private static final WeakReference<Integer> ref = new WeakReference<>(10);

5-2. 외부 캐시, 불변 객체, 리로드 설계의 중요성

  • Redis, Guava Cache 등 외부 캐시 사용
  • 불변 객체(static final)로 변경 가능성 최소화
  • 클래스 언로드가 가능한 구조 설계 필요

References

https://gmoon92.github.io/jvm/memory/static/2025/05/24/jvm-static-gc-guid.html

반응형