티스토리 뷰
목차
1. Java 프로그램 실행 과정 다시 짚고 가기
- .java -> 컴파일 -> .class (바이트코드 생성)
- JVM이 Class Loader로 로딩
- 메모리 영역(Runtime Data Area)에 적재
- 실행 엔진(Execution Engine)이 해석 & 실행
- 실행 중 발생하는 객체/변수 등이 JVM 메모리 영역에 저장됨
- 즉, 우리가 작성한 모든 Java 코드는 결국 JVM 메모리 공간을 점유하게 되며, 메모리 구조의 이해 = 성능과 안전성 이해의 첫걸음
2. JVM의 메모리 영역 정리 (Java 8 기준)
📌 JVM Runtime Data Area 구성
| 영역 | 설명 | 생성 시점 | 스레드 공유 여부 |
| Heap | 객체 인스턴스 저장, GC의 대상 | 클래스 로딩 시 | ✅ 공유 |
| Method Area (-> MetaSpace) | 클래스 정보, static 변수, constant pool | 클래스 로딩 시 | ✅ 공유 |
| Stack | 지역 변수, 참조 주소, 메서드 호출 정보 | 스레드 생성 시 | ❌ 개별 |
| PC Register | 현재 실행 중인 명령어 주소 | 스레드 생성 시 | ❌ 개별 |
| Native Method Stack | JNI를 통한 C/C++ 실행 시 사용 | 스레드 생성 시 | ❌ 개별 |
3. Heap 영역의 상세 구조
GC는 Heap을 중심으로 작동한다.
🔷 Heap 내부 구조 (Java 8 기준)
Heap
└─ Young Generation
├─ Eden
└─ Survivor 0 / Survivor 1
└─ Old Generation
📌 Young Generation
- 객체가 처음 생성되는 공간
- GC가 자주 발생(Minor GC)
- 대부분 객체는 이곳에서 생성되고 바로 소멸됨
📌 Eden
- 객체가 제일 먼저 생성되는 공간
- 생존 시 Servivor 영역으로 이동
📌 Survivor 0 / 1
- Eden에서 살아남은 객체들이 일시적으로 이동하는 공간
- Survivor 영역을 왔다 갔다 하며 생존 횟수(teruring threshold)를 넘기면 Old로 이동
📌 Old Generation
- 오래 살아남은 객체가 저장되는 공간
- Full GC(또는 Major GC)의 대상이 됨
4. Method Area (-> metaSpace)
📌 Java 8부터 PermGen -> MetaSpace로 변경
| PermGen | MetaSpace |
| JVM 메모리 내부 | Native 메모리 사용 (OS에 의존) |
| 사이즈 고정 -> OOM발생 가능 | 제한 없음 (옵션으로 설정 가능) |
클래스 정보(Class metadata), static 필드, constant pool 등이 저장됨
실무에서 클래스 수가 많아지면 OOM in MetaSpace 발생 가능
5. Stack 영역
- 스레드마다 독립적인 공간
- 각 메서드 호출 시 스택 프레임 생성
- 지역 변수, 매개 변수, 리턴 주소 등 저장
StackOverflowError는 재귀 호출이 너무 깊어질 때 발생
6. GC(Garbage Collection)의 역할과 전략
📌 GC의 목적
- 개발자가 명시적으로 free() 하지 않아도 메모리를 자동으로 회수
- 성능에 큰 영향 -> GC가 자주/오래 발생하면 애플리케이션 지연 발생
🔁 GC 동작 원리 (기본 흐름)
- Mark -> 사용 중인 객체 식별
- Sweep -> 사용하지 않는 객체 제거
- Compact -> 메모리 조각 정리 (Old 영역 중심)
🌀 GC의 종류
| 구분 | 설명 |
| Minor GC | Young 영역에서 발생, 빠르고 자주 일어남 |
| Major GC (Full GC) | Old 영역 포함 전체 GC, 느리고 애플리케이션 일시 정지 (Stop-the-world 발생) |
7. 주요 GC 알고리즘
| GC 종류 | 특징 | 설명 |
| Serial GC | 단일 스레드 | 소형 어플리케이션용 |
| Parallel GC | 멀티스레드 | Throughput 중심, 기본 GC 방식 |
| CMS (Concurrent Mark Sweep) | 응답 시간 최소화 | Mark-Sweep을 병렬로 수행, stop-the-world 시간 감소 |
| G1 GC | Java 9+ 기본 | Young/Old 영역을 Region 단위로 분할, 병렬 GC + 예측 가능성 높음 |
CMS는 현재 G1 GC로 대체 권장됨
8. 실무에서 발생하는 메모리 문제 유형
| 문제 | 원인 | 해결 방향 |
| OOM (OutofMemoryError) | 힙 or 메타스페이스 부족 | 힙 사이즈 조정, 객체 참조 해제 |
| Full GC 반복 | Old 영역 꽉 참 | GC 튜닝, 객체 생명주기 단축 |
| 클래스 로딩 메모리 초과 | PermGen/MetaSpace 부족 | -XX:MaxMetaspaceSize 조정 |
| StackOverflowError | 무한 재귀 | 재귀 탈출 조건 확인 |
9. GC 튜닝 시 주요 JVM 옵션
# Heap 영역 크기
-Xms512m # 초기 힙 사이즈
-Xmx1024m # 최대 힙 사이즈
# GC 로그 출력
-verbose:gc
-Xloggc:gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
# GC 종류 지정
-XX:+UseG1GC
-XX:+UseParallelGC
-XX:+UseConcMarkSweepGC
✅ 마무리 요약
- Java의 메모리는 Heap, Stack, Method Area 등으로 나뉘며 각자 역할이 다르다.
- GC는 주로 Heap 대상으로 하며, Young -> Old 객체로 옮겨가며 관리한다.
- GC 종류는 애플리케이션 특성에 따라 선택해야 하며, G! GC가 현재 가장 일반적이다.
- 메모리 관련 문제는 흔히 발생하며, JVM 튜닝과 GC 로그 분석 능력이 실무에서 중요하다.
🔜 다음 포스팅 주제로는 객체 지향의 4대 특성과 SOLID 원칙에 대해 보다 깊게 파고들어가 보려고 한다.
'IT > Java' 카테고리의 다른 글
| ☕ JVM 구조와 동작 원리 - Java 개발자라면 반드시 이해하고 있어야 할 기본기 (1) | 2025.04.14 |
|---|---|
| 어떤 버전의 JDK를 사용해야 할까? (3) | 2024.03.23 |