힙 메모리(Heap Memory) 구조 : Young·Old·Metaspace
자바 힙 메모리(Heap Memory) 는 new 키워드로 생성된 객체‧배열이 저장되는 공간이며, 가비지 컬렉션(Garbage Collection) 으로 자동 관리됩니다. 힙 구조를 깊이 이해하면 OutOfMemoryError 예방과 GC 튜닝으로 성능을 끌어올릴 수 있습니다.
힙 메모리란?
힙은 JVM이 확보한 공유 메모리로, 모든 스레드가 동시 접근할 수 있습니다.
객체가 더 이상 참조되지 않으면 가비지 컬렉터가 회수해 메모리 누수를 방지합니다.
힙 메모리 3-계층 구조
| 영역 | 주요 내용 | GC 종류 | 특징 |
|---|---|---|---|
| Young Generation | 생성된 지 얼마 안 된 객체 | Minor GC | 짧은 수명, Eden + Survivor(S0/S1) |
| Old Generation | 여러 번 Minor GC를 살아남은 장수 객체 | Major / Full GC | 길고 큰 객체, GC 빈도 낮지만 Pause 길음 |
| Metaspace(JDK 8+) | 클래스 메타데이터, 상수 풀 | 클래스 Unload 시 | 힙 외부 네이티브 메모리 사용 |
1. Young Generation
- Eden – 객체가 처음 놓이는 공간
- Survivor S0/S1 – Eden에서 살아남은 객체가 ping-pong 방식으로 이동
- Minor GC 가 빈번해 짧은 Stop-The-World 를 유발하지만 속도가 빠릅니다.
2. Old Generation
- 일정 Age(기본 15) 이상 살아남은 객체가 Promotion 됩니다.
- 메모리가 부족하면 Major GC 가 실행되어 긴 지연이 발생할 수 있습니다.
3. Metaspace (旧 PermGen)
- 클래스 로딩 시 메타데이터·정적 변수 등을 저장합니다.
XX:MaxMetaspaceSize로 크기를 제한할 수 있습니다.
힙 메모리 동작 흐름
- 객체 생성 → Eden에 배치
- Minor GC → 사용되지 않는 Eden 객체 제거, 생존 객체는 S0/S1 이동
- 객체 승격 → Survivor Age를 채운 객체가 Old Gen으로 이동
- Major / Full GC → Old Gen 청소 + 필요 시 전체 힙 압축
public class HeapDemo {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) { // 메모리 폭증
list.add(new byte[1_000_000]); // 1 MB 객체
}
}
}
위 코드를 java -Xmx128m HeapDemo 로 실행하면 OutOfMemoryError: Java heap space 가 재현됩니다.
JVM 힙 크기 설정 팁
Xms512m– 힙 초기 크기Xmx2g– 힙 최대 크기XX:+UseG1GC– 저지연 G1 GC 사용XX:MaxGCPauseMillis=200– 목표 GC Pause 시간 힌트
힙 메모리 최적화 전략
- 짧은 객체 생명주기 유지 – 필요 이상으로 참조를 남겨두지 않기
- 배치 할당 (객체 풀) – 반복 생성 비용·GC 부담 완화
- GC 로그 분석 (
Xlog:gc*) – Minor/Major 비율·Pause 패턴 확인 후 튜닝 - Metaspace 한도 설정 – 클래스 동적 생성이 많은 시스템의 메모리 폭주 방지
정리 질문
-
Young Gen 크기를 늘리면 성능이 좋아질까요?
객체 생성·소멸이 많은 애플리케이션은 Minor GC 횟수가 줄어 성능 개선 효과가 있습니다.
-
Metaspace도 가비지 컬렉션 대상인가요?
네, 클래스 언로딩 단계에서 회수되지만 빈도가 낮습니다.
-
G1 GC는 언제 선택하나요?
힙이 4 GB 이상이거나 지연 시간(Pause) 요구가 까다로운 서버 애플리케이션에 적합합니다.
-
System.gc()호출은 안전한가요?강제 Full GC 로 응답 지연을 유발할 수 있으므로, 프로파일링 후 필요한 경우에만 사용하세요.
-
메모리 누수를 GC가 자동 해결하나요?
객체가 여전히 참조되고 있으면 GC가 회수할 수 없습니다. 코드에서 참조를 해제해야 합니다.
댓글남기기