Java 면접 — JVM 메모리 구조 (Q1~Q10)
1. JVM 메모리 구조 (Q1 ~ Q10)
Q1. JVM 메모리 구조를 설명하세요
모범 답변
JVM 메모리는 크게 다음 영역으로 구분됩니다.
graph LR
A[JVM Memory] --> B[Heap]
A --> C[Non-Heap]
B --> D[Young Gen]
B --> E[Old Gen]
C --> F[Metaspace]
Heap 영역:
- Young Generation: Eden + Survivor(S0, S1). 새로 생성된 객체가 위치. Minor GC 발생
- Old Generation: Young에서 살아남은 객체가 승격. Major/Full GC 발생
Non-Heap 영역:
- Metaspace (Java 8+): 클래스 메타데이터 저장. Java 7의 PermGen을 대체. 네이티브 메모리 사용
- Code Cache: JIT 컴파일된 코드
- Stack: 스레드별 독립. 메서드 호출 프레임, 지역 변수
- PC Register: 현재 실행 중인 JVM 명령어 주소
비유: JVM 메모리는 회사 건물입니다. Heap은 공유 사무실(모든 스레드가 접근), Stack은 개인 책상(스레드마다 독립), Metaspace는 도서관(클래스 정보 보관)
면접 포인트 펼치기
**꼬리질문:** Java 8에서 PermGen이 Metaspace로 바뀐 이유는? PermGen은 고정 크기라 `OutOfMemoryError: PermGen space` 오류가 빈번했습니다. Metaspace는 네이티브 메모리를 사용하여 동적으로 확장됩니다. 단, 메모리 누수가 있으면 네이티브 메모리를 계속 소비합니다. **꼬리질문:** 스택 오버플로우는 왜 발생하나요? 메서드 호출마다 스택 프레임이 쌓입니다. 무한 재귀나 깊은 재귀 호출 시 스택 크기 한계를 초과하여 `StackOverflowError` 발생. JVM 옵션 `-Xss`로 스택 크기 조절 가능.Q2. Minor GC와 Major GC의 차이는?
모범 답변
Minor GC:
- Young Generation 대상
- 빠르고 자주 발생 (밀리초 단위)
- STW(Stop-The-World) 짧음
- Eden이 가득 차면 트리거
Major GC (Full GC):
- Old Generation 대상 (보통 Heap 전체 포함)
- 느리고 드물게 발생 (초 단위)
- STW 길어 응답 지연 발생
- Old Gen이 가득 차거나
System.gc()호출 시 트리거
객체 승격 과정:
- 새 객체 → Eden
- Minor GC 생존 → Survivor (S0 또는 S1)
- GC 생존 횟수가 임계값(기본 15) 초과 → Old Generation
비유: Minor GC는 매일 하는 분리수거, Major GC는 한 번씩 하는 대청소. 대청소할 때는 모든 가족이 청소에만 집중해야 합니다(STW).
면접 포인트 펼치기
**꼬리질문:** GC 튜닝 시 주로 어떤 옵션을 조정하나요? - `-Xms`, `-Xmx`: Heap 초기/최대 크기 (동일하게 설정 권장 — 동적 조정 오버헤드 제거) - `-XX:NewRatio`: Young:Old 비율 - `-XX:SurvivorRatio`: Eden:Survivor 비율 - `-XX:MaxTenuringThreshold`: 승격 임계값Q3. GC 알고리즘의 종류를 설명하세요
모범 답변
| GC | 특징 | 적합 환경 |
|---|---|---|
| Serial GC | 단일 스레드, 가장 단순 | 소형 앱, 테스트 |
| Parallel GC | 멀티 스레드, 처리량 중시 | Java 8 기본 (서버) |
| CMS GC | 동시 마킹, 지연 최소화 | Java 9 deprecated |
| G1 GC | Region 기반, 지연 예측 | Java 9 기본, 4GB+ Heap |
| ZGC | 초저지연 (1~15ms), 대용량 | Java 15+, 수백GB Heap |
| Shenandoah | 동시 압축, 초저지연 | RedHat 제공 |
G1 GC 핵심 원리:
Heap을 고정 크기 Region으로 분할. 가장 많은 가비지를 가진 Region(Garbage First)을 우선 수집. 목표 지연 시간 설정 가능(-XX:MaxGCPauseMillis).
비유: G1 GC는 쓰레기가 가장 많은 방부터 청소하는 청소부. CMS는 집 안에서 사람들이 생활하는 중에 조용히 청소합니다.
면접 포인트 펼치기
**꼬리질문:** ZGC와 G1 GC의 선택 기준은? G1 GC: Heap 4GB~16GB, 지연 100ms 이하 목표. 안정적이고 검증된 선택. ZGC: Heap 수백GB, 지연 10ms 이하 필요. 트레이드오프: CPU 사용량이 다소 높습니다.Q4. 메모리 누수(Memory Leak)가 Java에서 발생하는 상황은?
모범 답변
GC가 있어도 메모리 누수는 발생합니다. GC는 참조가 없는 객체만 수집하기 때문입니다.
주요 메모리 누수 패턴:
- Static 컬렉션에 계속 추가:
static Map에 추가하고 제거하지 않음 - 리스너/콜백 미해제: 이벤트 리스너를 등록 후 제거하지 않음
- 잘못된 equals/hashCode:
HashSet에 넣은 객체를 찾지 못해 중복 축적 - 내부 클래스 참조: 익명 클래스가 외부 클래스 인스턴스를 암묵적으로 참조
- ThreadLocal 미제거: 스레드 풀 환경에서
ThreadLocal.remove()누락
// 위험한 패턴 — ThreadLocal 누수
private static ThreadLocal<ExpensiveObject> threadLocal = new ThreadLocal<>();
public void process() {
threadLocal.set(new ExpensiveObject());
try {
// 처리
} finally {
threadLocal.remove(); // 반드시 제거!
}
}
댓글