Post

[Java] 가비지 컬렉터(Garbage Collection)

📌 들어가며

C/C++에서는 개발자가 메모리 할당과 해제를 일일이 직접 관리해야 한다. 실수하면 메모리 누수나 크래시로 이어진다. 자바는 이 부담을 가비지 컬렉터(GC)에게 맡긴다.

GC(Garbage Collection)란? JVM의 Heap 영역에서 동적으로 할당했던 메모리 중 더 이상 필요 없는 영역을 주기적으로 삭제하는 프로세스. 덕분에 개발자가 수동으로 메모리를 해제할 필요가 없다.

1
2
// System.gc() — GC 실행을 '제안'한다 (강제는 아님)
// Runtime.getRuntime().gc() 와 사실상 동일

⚠️ GC의 단점

  • 메모리가 언제 해제되는지 개발자가 정확히 알 수 없다.
  • GC가 동작하는 동안 다른 작업이 멈춰 오버헤드가 발생한다.

1. Reachable vs Unreachable

Desktop View

객체는 실제로 Heap 영역에 생성되고, Root Area(스택 등)는 그 객체의 주소만 참조한다. 참조 여부에 따라 상태가 갈린다.

상태의미GC 대상
Reachable어딘가에서 참조되고 있음
Unreachable아무 데서도 참조되지 않음✅ (제거 대상)

GC는 Unreachable 상태의 객체를 주기적으로 제거한다.


2. Mark And Sweep 알고리즘

Desktop View

GC의 동작 원리로, Root에서 객체에 접근 가능한지를 메모리 해제의 기준으로 삼는다. 3단계로 진행된다.

단계동작
① MarkRoot부터 그래프를 순회하며 참조되는(연결된) 객체를 표시
② Sweep표시되지 않은(Unreachable) 객체를 Heap에서 제거
③ CompactSweep 후 흩어진 객체를 Heap 시작 주소로 모아 압축

3. GC 대상 Heap 영역 — 세대(Generation)

Desktop View

효율적인 GC를 위해 Heap은 세대별로 나뉜다.

1
2
3
4
5
┌──────────── Young Generation ────────────┐  ┌─ Old ─┐  ┌ Metaspace ┐
│  Eden      Survivor0    Survivor1         │  │       │  │ (meta 정보)│
└───────────────────────────────────────────┘  └───────┘  └───────────┘
   최초 생성       살아남으면 이동               오래 살아남으면
                                                promotion
영역설명GC 종류
Eden객체가 최초로 생성되는 곳Minor GC
Survivor 0/1Eden에서 살아남은 객체가 이동Minor GC
Old Generation오래 살아남은 객체가 이동(promotion)Major GC
Metaspace (JDK 1.8+)클래스 meta 정보, intern 문자열 등
GC 종류대상특징
Minor GCYoung Generation빠름, 빈번
Major GCOld Generation느림, Stop-the-world 발생

⚠️ Stop-the-world: Major GC가 실행되면 GC를 제외한 모든 스레드가 작업을 멈춘다. 이 작업이 잦으면 성능 문제가 된다.


4. 동작 과정 (age-bit)

객체는 Eden에서 태어나 Minor GC를 살아남을 때마다 age-bit가 1씩 증가하고, 임계값에 도달하면 Old로 승격된다.

1
2
3
4
5
① Eden 생성 (age 0)
② Eden 꽉 참 → Minor GC → 살아남으면 Survivor로 이동 (age++)
③ 반복하며 Survivor0 ↔ Survivor1 사이 이동, age 계속 증가
④ age-bit가 임계값 도달 → Old로 이동 (promotion)
⑤ Old도 꽉 참 → Major GC (Stop-the-world)
과정이미지
Eden에 age 0으로 할당
Eden 꽉 참 → Minor GC
Survivor로 이동, age++
Survivor 교차 이동
임계값 도달 → promotion
Old 꽉 참 → Major GC

5. GC Policy — 어떤 방식으로 수거할까

Old 영역이 가득 차 Major GC가 동작할 때, 어떤 방식으로 수행하느냐가 성능에 큰 영향을 준다.

정책옵션특징
Serial GC-XX:+UseSerialGCMark&Sweep, 단일 스레드. 메모리·코어 적을 때
Parallel GC-XX:+UseParallelGCSerial과 같은 알고리즘을 여러 스레드로. Throughput GC
Parallel Old GC-XX:+UseParallelOldGCOld 영역에 Mark&Summary&Compaction 적용
CMS GC-XX:+UseConcMarkSweepGCSTW 최소화(동시 수행), 단 CPU·메모리 더 쓰고 compaction 미제공
G1GCHeap을 바둑판처럼 region으로 나눠 수거. CMS 대체, 성능 우수

💡 CMSinitial mark → concurrent mark → remark → concurrent sweep 단계로 STW 시간을 짧게 가져가지만, compaction이 없어 메모리 단편화가 생길 수 있다. G1GC는 young/old를 한 방식(region)으로 통합 관리해 이를 개선했다.

JNI (Java Native Interface)

Desktop View

Runtimegc() 메소드를 보면 native가 붙어 있다. JNI는 C/C++로 작성된 모듈을 자바에서 호출할 수 있게 해주는 기능이다. (MS가 공개한 자바 GC 툴킷도 참고할 만하다.)


📝 정리

1
2
3
4
5
6
Garbage Collection
├─ 목적       Heap의 Unreachable 객체를 자동 회수
├─ 알고리즘   Mark → Sweep → Compact
├─ 세대       Eden → Survivor(Minor GC) → Old(Major GC, STW)
├─ age-bit    살아남을수록 증가 → 임계값 시 Old로 promotion
└─ 정책       Serial / Parallel / CMS / G1GC (성능 트레이드오프)
개념한 줄 정의
Reachable/Unreachable참조 여부, Unreachable이 수거 대상
Minor/Major GCYoung 수거 / Old 수거(STW)
Stop-the-worldGC 중 모든 스레드 정지
G1GCregion 기반의 현대적 GC

GC는 자바의 편리함을 떠받치는 핵심 메커니즘이다. “Unreachable 객체를 Mark&Sweep으로 수거하고, 세대별로 관리하며, 정책에 따라 성능이 갈린다”는 큰 그림을 잡아두면 실무의 GC 튜닝도 이해하기 쉬워진다.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.