본문 바로가기
Language/Java

[JAVA] 자바 가비지 컬렉션(GC) : 메모리 관리의 예술과 작동 원리

by Papa Martino V 2026. 1. 14.
728x90

자바 가비지 컬렉션(GC)
자바 가비지 컬렉션(GC)

 

자바(Java)가 개발자들에게 사랑받는 여러 이유 중 하나는 바로 가비지 컬렉션(Garbage Collection, GC)입니다. C나 C++ 같은 언어에서는 개발자가 직접 메모리를 할당하고 해제해야 하는 부담이 있었지만, 자바는 이 복잡한 과정을 JVM(Java Virtual Machine)이 대신 처리해 줍니다. 단순한 자동화 기능을 넘어, GC는 자바의 안정성과 생산성을 책임지는 핵심 엔진입니다. 오늘은 이 가비지 컬렉션이 무엇인지, 그리고 그 복잡한 내부 메커니즘이 어떻게 작동하는지 깊이 있게 탐구해 보겠습니다.


1. 가비지 컬렉션(GC)은 왜 필요한가요?

컴퓨터 프로그램은 실행 중에 끊임없이 메모리를 사용합니다. 객체를 생성하고, 데이터를 저장하고, 함수를 호출하는 모든 과정이 메모리 할당을 동반합니다. 만약 프로그램이 더 이상 사용하지 않는 메모리를 제대로 해제하지 않으면, 해당 메모리 공간은 계속 점유되어 결국 시스템 전체의 메모리가 고갈되는 '메모리 누수(Memory Leak)' 현상이 발생합니다. 이는 프로그램의 성능 저하를 넘어 시스템 다운으로 이어질 수 있습니다. GC는 개발자가 이러한 메모리 관리의 부담에서 벗어나 오직 핵심 비즈니스 로직에만 집중할 수 있도록 돕는 자바의 혁신적인 기능입니다. "사용하지 않는 메모리를 자동으로 회수한다"는 개념은 자바가 엔터프라이즈 환경에서 강력한 신뢰성을 구축하는 데 결정적인 역할을 했습니다.


2. 가비지 컬렉션의 기본 원리: Reachability

GC는 어떤 객체가 '쓸모 있는' 객체이고, 어떤 객체가 '가비지(Garbage, 쓰레기)'인지 어떻게 판단할까요? 그 핵심 원리는 바로 '도달 가능성(Reachability)'입니다. 어떤 객체가 루트(Root)로부터 참조(Reference)될 수 있다면 그 객체는 '도달 가능한(Reachble)' 상태이며, 사용 중인 객체로 간주됩니다. 반대로 루트로부터 어떤 경로로도 도달할 수 없는 객체는 '도달 불가능한(Unreachable)' 상태이며, 가비지 컬렉션의 대상이 됩니다. 여기서 '루트'란 스택(Stack) 영역의 변수, 메서드 영역의 정적 변수, JNI(Java Native Interface)를 통해 생성된 객체 등 프로그램 실행에 직접적으로 필요한 참조들을 의미합니다.


3. HotSpot JVM의 GC 작동 방식: 세대(Generational) 가설

자바의 GC는 단순히 모든 객체를 한 번에 검사하는 비효율적인 방식이 아닙니다. 대부분의 JVM, 특히 Oracle HotSpot JVM은 '세대(Generational) 가설'을 기반으로 메모리 영역을 효율적으로 나누어 관리합니다.

세대 가설은 두 가지 전제를 가지고 있습니다.

  • Weak Generational Hypothesis: 대부분의 객체는 금방 죽는다 (Young Generation)
  • Strong Generational Hypothesis: 오래 살아남은 객체는 계속 살아남는 경향이 있다 (Old Generation)

이 가설에 따라 힙(Heap) 메모리 영역은 크게 세 부분으로 나뉩니다.

  1. Young Generation (새롭게 생성된 객체):
    • Eden Space: 대부분의 새 객체가 처음 할당되는 공간입니다.
    • Survivor Space (S0, S1): Eden에서 살아남은 객체들이 잠시 머무르는 공간입니다. 두 개의 Survivor Space가 번갈아 사용됩니다.
    Young Generation에서 발생하는 GC를 Minor GC라고 합니다. Minor GC는 비교적 빠르게 진행되며, 대부분의 객체가 이 단계에서 소멸합니다.
  2. Old Generation (오랫동안 살아남은 객체):Young Generation에서 여러 번의 Minor GC를 거치고도 살아남은 객체들은 Old Generation으로 승격(Promotion)됩니다. 이 영역은 크기가 크고 GC 발생 빈도가 낮습니다.
  3. Old Generation에서 발생하는 GC를 Major GC (Full GC)라고 합니다. Major GC는 Minor GC보다 훨씬 많은 시간이 소요되며, 일반적으로 전체 힙을 검사하기 때문에 애플리케이션의 성능에 큰 영향을 미칠 수 있습니다.

4. 다양한 GC 알고리즘의 종류와 특징

JVM은 애플리케이션의 특성과 요구 사항에 따라 다양한 GC 알고리즘을 제공합니다. 주요 GC 알고리즘은 다음과 같습니다.

GC 알고리즘 주요 특징 적합한 시나리오
Serial GC 싱글 스레드 GC, 가장 단순하고 효율성 낮음. Stop-The-World 시간 김. 클라이언트 환경, 소규모 서버 (-XX:+UseSerialGC)
Parallel GC 멀티 스레드로 Young/Old GC 수행. 처리량(Throughput) 중시. Stop-The-World 발생. 대규모 배치 처리, 높은 처리량이 중요한 서버 (-XX:+UseParallelGC)
CMS GC (Deprecated) Low Pause GC. Stop-The-World 시간을 최소화하려 노력. 단편화 문제. 응답 시간 중요 앱 (Java 9부터 Deprecated)
G1 GC Heap을 Region으로 분할 관리. 목표 지연시간(Pause Time) 설정 가능. 처리량 및 지연시간 균형. 대용량 메모리, 멀티 코어 시스템, 현대적인 대부분의 앱 (Java 9+ Default)
ZGC, Shenandoah GC 매우 낮은 지연 시간(Very Low Latency)을 목표. 극단적인 대용량 힙(TB 단위)에서도 짧은 Stop-The-World. 초고성능, 실시간 처리 요구 앱 (Java 11+ Experimental/Production)

Stop-The-World (STW): GC가 실행되는 동안 애플리케이션 스레드가 모두 멈추는 현상입니다. GC 알고리즘의 발전은 이 STW 시간을 최소화하는 방향으로 이루어져 왔습니다.


5. GC 최적화의 중요성: 개발자의 역할

GC가 자동이라고 해서 개발자가 완전히 손을 놓을 수 있는 것은 아닙니다. 잘못된 코드 작성 습관은 GC의 비효율성을 초래하고, 결국 애플리케이션의 성능 저하로 이어집니다.

  • 불필요한 객체 생성 자제: 짧은 수명을 가진 객체를 과도하게 생성하는 것은 GC 부하를 높입니다.
  • 객체 풀(Object Pool) 사용: 재사용 가능한 객체를 미리 생성해 두는 방식으로 GC 발생 빈도를 줄일 수 있습니다.
  • 적절한 GC 알고리즘 선택: 애플리케이션의 특성(처리량 vs 지연 시간)에 맞춰 최적의 GC를 선택하고 튜닝해야 합니다.
  • 메모리 사용량 모니터링: JConsole, VisualVM 등 JVM 모니터링 도구를 사용하여 힙 사용량과 GC 발생 패턴을 주기적으로 분석해야 합니다.

결론: 자바의 숨겨진 영웅, GC

자바 가비지 컬렉션은 단순히 "자동 메모리 관리"를 넘어, 자바 언어의 핵심적인 강점이자 현대 소프트웨어 시스템의 안정성을 보장하는 핵심 기술입니다. GC의 원리와 다양한 알고리즘을 이해하고, 효과적으로 최적화하는 것은 자바 개발자로서 반드시 갖춰야 할 역량입니다. 개발자가 메모리 해제의 고통에서 벗어나 더 창의적인 문제 해결에 집중할 수 있게 해준 가비지 컬렉션은 자바 생태계의 숨겨진 영웅이라 할 수 있습니다.


참고 문헌 및 출처

 

728x90