Garbage Collection
Garbage Collection (GC)
📝 GC란?
JVM에서 메모리 관리를 자동으로 수행하는 프로세스
개발자가 명시적으로 메모리 관리 불필요
🔑 Weak Generational Hypothesis
GC 도입의 전제 가설
1. 대부분의 객체는 금방 접근 불가능 상태가 됨
for (int i = 0; i < 1000; i++) {
SampleObj obj = new SampleObj();
obj.doTest(i);
}
마지막 한 번 제외 999번의 객체는 즉시 unreachable
2. 오래된 객체에서 젊은 객체로의 참조는 적음
SampleObj obj = new SampleObj();
obj.setValue(1);
doTest(obj);
객체 생성 후 다른 메서드에 전달하면 다시 참조 안 함
💡 GC의 역할
- 메모리 할당
- 사용 중인 메모리 인식
- 사용하지 않는 메모리 인식
🗂️ GC 수행 영역: Heap
JVM 메모리 영역:
- 클래스 영역
- 자바 스택
- Heap ← GC 수행
- 네이티브 메서드 스택
이유: 새로운 객체가 Heap에 할당되기 때문
📦 Heap 영역 구조
┌─────────────────────────────┐
│ New/Young 영역 │
│ (Eden + Survivor1 + Survivor2) │
├─────────────────────────────┤
│ Old 영역 │
├─────────────────────────────┤
│ Perm 영역 │
└─────────────────────────────┘
New/Young: 생성된 지 얼마 안 된 객체
Old: 생성된 지 오래된 객체
Perm: Class, Method 등 코드 저장
👶 Minor GC
New/Young 영역의 GC
알고리즘: Copy & Scavenge
Young 영역 구조
Eden:
- 객체가 생성되자마자 저장
- Eden 가득 차면 Minor GC 발생
- 살아남은 객체는 Survivor로 이동
Survivor:
- Survivor1, Survivor2로 나뉨
- 한 Survivor 가득 차면 살아남은 객체를 다른 Survivor로 이동
- 항상 하나는 비어있어야 함
- 오래된 객체는 Old로 이동 (Promotion)
Object Aging
Survivor 이동 시마다 age 값 증가
Object Header에 기록
age를 보고 Old로 Promotion 결정
Minor GC 특징
✅ 속도 매우 빠름 ✅ 작은 크기 메모리 콜렉팅에 효과적 ✅ 자주 일어남 → 짧은 알고리즘 적합
🧓 Major GC (Full GC)
Old 영역의 GC
알고리즘: Mark & Compact
동작 과정
- Mark: 참조 연결 안 된 객체 표시
- Compact: 표시된 객체 삭제
Major GC 특징
❌ 속도 매우 느림 ❌ Full GC 도중 애플리케이션 멈춤 (Stop The World) ❌ 성능과 안정성에 큰 영향
🔄 GC 발생 시나리오
1. 객체 생성
┌──────┐
│ Eden │ ← 새 객체
└──────┘
2. Eden 가득 참
Minor GC 발생
↓
참조 없는 객체 삭제
참조 중인 객체 → Survivor
3. Survivor 가득 참
Minor GC 발생
↓
참조 없는 객체 삭제
참조 중인 객체 → 다른 Survivor
4. 반복 후 Old로 이동
Survivor에서 계속 살아남음
↓
Old 영역으로 Promotion
5. 큰 객체
Eden → Survivor보다 큰 객체
↓
바로 Old 영역으로 이동
⚙️ GC 동작 방식
1. Stop The World
GC 실행을 위해 JVM이 애플리케이션 실행 중단
GC thread 제외 모든 thread 작업 중단
GC 완료 후 작업 재개
성능 개선 = Stop The World 시간 줄이기
2. Mark and Sweep
Mark: 사용되는 메모리 식별
Sweep: 사용 안 되는 메모리 해제
과정:
- Stop The World
- 스택의 모든 변수/객체 스캔
- 참조 객체 Mark
- Mark 안 된 객체 Sweep
3. Compact
객체들을 가까운 곳으로 모음
Heap 메모리 아래쪽으로 이동
목적: 메모리 파편화 최소화
파편화: 비어있는 공간이 떨어져 있어 큰 객체 할당 어려움
🚨 GC가 중요한 이유
Minor GC: 0.5~1초 → 큰 문제 없음
Full GC: 시간 오래 걸림 → 애플리케이션 멈춤
문제:
- 사용자 요청이 Queue에 대기
- 순간적으로 요청 한꺼번에 처리
- 과부하로 장애 발생 가능
결론: GC 최적화가 시스템 안정성과 성능에 중요
🔧 GC 알고리즘
1. Serial GC
32bit JVM, Single Thread 애플리케이션
특징:
- Minor/Major GC 모두 Single Thread
- Mark-Sweep-Compact 알고리즘
2. Parallel GC (Throughput GC)
Java 8 기본 GC
특징:
- Minor GC: Multi Thread
- Major GC: Single Thread
- 메모리 충분, 코어 많을 때 유리
3. Parallel Old GC
Java 8 디폴트 (엄밀히)
특징:
- Major GC도 Multi Thread
- Mark-Summary-Compact 알고리즘
4. CMS Collector (Concurrent Mark-Sweep)
Low Latency GC
단계:
- Initial Mark: 가까운 객체만 (짧음)
- Concurrent Mark: 참조 확인 (STW 없음)
- Remark: 새로 추가/끊긴 객체 확인
- Concurrent Sweep: 쓰레기 정리 (STW 없음)
장점: Stop The World 시간 매우 짧음
단점:
- 메모리/CPU 많이 사용
- 메모리 파편화
- Compaction 기본 제공 안 함
5. G1 Collector (Garbage First)
Java 9 기본 GC
특징:
- Heap을 Region으로 나눔
- Humongous: 큰 객체 저장
- Available/Unused: 미사용 Region
- 가장 많이 공간 있는 곳부터 회수
장점:
- CMS의 CPU/메모리 파편화 단점 해결
G1 GC Cycle
Young-Only Phase:
- Minor GC 수행
- Old Generation 비율 초과 시 Major GC
Space Reclamation Phase:
- Mixed GC 수행
- Mark 단계 없음
- STW 빈도 감소
❓ 면접 질문 예시
Q1. GC의 실행 시점은?
답변: Minor GC는 Young 영역(Eden 또는 Survivor)이 가득 찼을 때 실행됩니다. Major GC는 Old 영역이 가득 찼을 때 실행되며, Full GC는 Heap 전체가 가득 찼을 때 실행됩니다.
Q2. GC가 어떤 원리로 동작하나요?
답변: GC는 1) Stop The World로 모든 애플리케이션 스레드를 중단하고, 2) Mark 단계에서 사용 중인 메모리를 식별하며, 3) Sweep 단계에서 사용하지 않는 메모리를 해제하고, 4) Compact 단계에서 메모리 파편화를 최소화하기 위해 객체들을 모읍니다.
Q3. Minor GC와 Major GC의 차이점은?
답변: Minor GC는 Young 영역에서 발생하며 Copy & Scavenge 알고리즘을 사용하고 속도가 매우 빠릅니다. Major GC는 Old 영역에서 발생하며 Mark & Compact 알고리즘을 사용하고 속도가 느리며 애플리케이션이 멈추는 Stop The World가 발생합니다.
Q4. Weak Generational Hypothesis란?
답변: GC 도입의 전제 가설로 1) 대부분의 객체는 금방 접근 불가능 상태가 되고, 2) 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다는 가설입니다. 이 때문에 Heap을 Young 영역과 Old 영역으로 나누어 관리합니다.
Q5. G1 GC의 특징은?
답변: G1 GC는 Heap을 바둑판처럼 Region으로 나누어 관리하며, 가장 많이 공간이 있는 곳부터 메모리를 회수합니다. CMS의 CPU 리소스 및 메모리 파편화 단점을 해결했으며, Java 9부터 기본 GC로 사용됩니다.
📚 원본 참고 자료
출처: 2023-CS-Study
- 링크: java_gc.md
- 내용: Garbage Collection, GC 알고리즘, Heap 구조