JVM 메모리 구조와 GC 튜닝



JVM 메모리 구조를 이해하고 GC를 튜닝하면 애플리케이션 성능을 크게 향상시킬 수 있습니다.



JVM 메모리 구조


┌─────────────────────────────────────────┐
│ JVM Memory │
├─────────────────────────────────────────┤
│ ┌─────────────────────────────────┐ │
│ │ Heap Memory │ │
│ │ ┌───────────┬───────────────┐ │ │
│ │ │ Young │ Old │ │ │
│ │ │ ┌─────┐ │ Generation │ │ │
│ │ │ │Eden │ │ │ │ │
│ │ │ ├─────┤ │ │ │ │
│ │ │ │S0│S1│ │ │ │ │
│ │ │ └─────┘ │ │ │ │
│ │ └───────────┴───────────────┘ │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Metaspace (Non-Heap) │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Thread Stacks │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘


주요 메모리 영역








영역저장 내용GC 대상
Eden새로 생성된 객체Minor GC
Survivor (S0, S1)Eden에서 살아남은 객체Minor GC
Old Generation오래 살아남은 객체Major GC
Metaspace클래스 메타데이터Full GC


GC 종류와 선택


# G1GC (기본, Java 9+, 균형잡힌 선택)
-XX:+UseG1GC

# ZGC (저지연, 대용량 힙, Java 15+)
-XX:+UseZGC

# Parallel GC (처리량 중시)
-XX:+UseParallelGC

# Shenandoah GC (저지연, Java 12+)
-XX:+UseShenandoahGC


주요 JVM 옵션


# 힙 메모리 설정
-Xms2g # 초기 힙 크기
-Xmx4g # 최대 힙 크기
-Xmn1g # Young Generation 크기

# Metaspace 설정
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m

# GC 로그
-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=10m

# 힙 덤프 (OOM 발생 시)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/heapdump.hprof


G1GC 튜닝


# 목표 pause time (기본 200ms)
-XX:MaxGCPauseMillis=100

# Region 크기 (1~32MB)
-XX:G1HeapRegionSize=16m

# 동시 GC 스레드 수
-XX:ConcGCThreads=4

# 힙 사용률 임계값
-XX:InitiatingHeapOccupancyPercent=45


ZGC 튜닝 (저지연)


# ZGC 활성화
-XX:+UseZGC

# 동시 GC 스레드
-XX:ConcGCThreads=2

# 최대 pause time 목표 (밀리초)
-XX:ZUncommitDelay=300


모니터링 도구


# jstat - GC 통계
jstat -gc PID 1000

# jmap - 힙 덤프
jmap -dump:format=b,file=heap.hprof PID

# jcmd - 다양한 진단
jcmd PID GC.heap_info
jcmd PID VM.flags

# VisualVM, JConsole (GUI)


GC 로그 분석


# GC 로그 예시
[2024-01-15T10:30:15.123+0900] GC(123) Pause Young (Normal)
(G1 Evacuation Pause) 512M->256M(1024M) 15.234ms

# 확인 포인트
- Pause time: 15.234ms (STW 시간)
- 힙 사용량: 512M → 256M
- 빈도: 너무 잦으면 Young Gen 증가 필요


문제 상황별 튜닝


# 1. OOM 발생
- 힙 크기 증가: -Xmx 증가
- 메모리 누수 확인: 힙 덤프 분석

# 2. GC pause가 너무 김
- G1GC: -XX:MaxGCPauseMillis 감소
- ZGC로 변경 고려

# 3. Full GC 빈번
- Old Gen 크기 증가
- 객체 생성 패턴 검토

# 4. Metaspace OOM
- -XX:MaxMetaspaceSize 증가
- 클래스 로딩 누수 확인


실전 설정 예시


# Spring Boot 웹 애플리케이션 (4GB 서버)
java -Xms2g -Xmx2g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-XX:+HeapDumpOnOutOfMemoryError
-Xlog:gc*:file=gc.log
-jar app.jar

# 대용량 배치 처리 (16GB 서버)
java -Xms8g -Xmx8g
-XX:+UseZGC
-XX:ConcGCThreads=4
-jar batch.jar