가비지 컬렉션(Garbage Collection)이란?
- 불필요해진 객체(더 이상 참조되지 않는 객체)를 자동으로 탐지하여 메모리에서 해제하는 JVM의 메모리 관리 기법
- C, C++과 달리
free()나 delete 같은 명시적 해제가 필요 없음 → 메모리 누수 위험 대폭 감소
GC의 동작 원리
객체 lifecycle
- 객체 생성:
new 등으로 힙에 메모리 할당
- 참조 유지: 하나 이상의 변수/필드에서 참조하면 "
reachable"
- 참조 소멸: 변수/필드에서 연결이 모두 끊기면 "
unreachable" 상태
- GC 대상: 더 이상 어떤 변수에서도 접근할 수 없는 객체는 가비지(Garbage)로 간주
GC의 트리거(언제 실행?)
- JVM이 힙의 사용량이 일정 임계치에 도달하거나, 명시적으로 System.gc() 호출 시
- JVM이 "언제" 실행할지는 자율적으로 판단 (일반적으로 자동)
JVM 메모리 구조와 GC
※ Young Generation, Old Generation 구분 예시
Generational GC 구조
- Young Generation:
- 새로 생성된 객체 저장 (Eden, Survivor S0/S1)
- 대부분의 객체는 생성 후 곧바로 소멸(“객체의 대부분은 오래 살아남지 않는다”)
- Old Generation:
- Young에서 살아남은(여러 GC를 견딘) 장수 객체 저장
- Metaspace(메타스페이스):
- 클래스 정보, static 변수 등 (PermGen은 자바8부터 Metaspace로 변경)
주요 GC 알고리즘(방식)
Mark and Sweep (표시-삭제)
Mark: Reachable(도달 가능한) 객체를 모두 표시
Sweep: 표시되지 않은 객체는 메모리에서 해제
Stop-the-world
- GC 수행 시 애플리케이션 스레드 모두 일시 정지
- GC 후에 다시 실행
- 짧게 끊기는 “멈춤 현상”이 단점
Minor GC vs Major GC
- Minor GC: Young Generation만 GC (일반적으로 짧고 빈번함)
- Major GC(Full GC): Old Generation 포함 전체 GC (더 느리고 애플리케이션 일시 정지 시간이 길다)
복사(Copying), 압축(Compaction), 참조 업데이트
- Young GC는 Copying 방식(Eden → Survivor)으로 빠르게 작동
- Old GC는 Mark-Sweep-Compact로 메모리 단편화 방지
주요 JVM GC 구현체
| GC 종류 | 특징 | 사용처/장단점 |
|---|
| Serial GC | 단일 스레드로 동작, 단순, 소규모 앱/테스트용 | 적은 메모리, 단일 CPU |
| Parallel GC | (Default) 다중 스레드로 Young GC, 빠른 Throughput | 일반 서버 앱, 성능 좋음 |
| CMS (Concurrent Mark-Sweep) | Old 영역을 병행으로 마킹/스윕 | Stop-the-world 최소화, 더 많은 CPU |
| G1 GC | Java 9 이상 기본, Region 단위 관리, Predictable | 대용량, 낮은 지연 |
| ZGC, Shenandoah | 극한의 저지연, 초대용량 시스템 | 최신 Java, 하드웨어 여유 필요 |
GC 튜닝 실무 팁
- JVM 옵션으로 GC 종류와 Heap 크기 설정
- 예:
-Xmx2g -Xms2g -XX:+UseG1GC
- 로그 분석으로 GC pause time, frequency 모니터링
- 예:
-XX:+PrintGCDetails -Xloggc:gc.log
- 객체 생성 최소화 & 참조 빨리 끊기 (ex. null 할당)
- 불필요한 Static, 캐시 객체 주의 (GC에서 살아남기 쉬움)
가비지 컬렉션의 한계/주의점
Stop-the-world 현상: GC 도중 모든 스레드가 멈춤 → 레이턴시 민감한 서비스(게임, 금융)에서 주의
- 메모리 누수: 참조가 남아 있으면(GC Root에 연결된 객체) GC가 회수 못함
- GC 튜닝 난이도: 워크로드에 따라 최적 세팅이 다름(서버, 클라우드 환경 등)
실제 코드 예시
public class GcExample {
public static void main(String[] args) {
for (int i = 0; i < 100_000; i++) {
String data = new String("data-" + i);
}
System.gc();
}
}
- 위 코드에서 data는 반복문이 끝나면 참조가 끊기므로 GC 대상
요약 표
| 용어/기능 | 설명 |
|---|
| Minor GC | Young 영역 GC (빠르고 짧음) |
| Major(Full) GC | Old 포함 전체 GC (길고 느림) |
| Stop-the-world | GC 중 JVM의 모든 스레드 일시 정지 |
| Mark-and-Sweep | 살아있는 객체 표시 후 미사용 객체 제거 |
| Generational GC | Young/Old 세대 구분, 객체 생존 기반 |
| G1, ZGC, CMS 등 | 최신 GC 전략, 저지연/대용량 지원 |
Reference