지난 포스팅에서 다룬 G1 GC는 메모리를 리전(Region)으로 나누어 효율성을 극대화한 훌륭한 가비지 컬렉터입니다. 하지만 최근 엔터프라이즈 환경에서 다루는 데이터의 규모가 폭발적으로 증가하면서, 수십 기가바이트(GB)를 넘어 테라바이트(TB) 단위의 거대한 힙(Heap) 메모리를 사용하는 시스템들이 등장하기 시작했습니다.
힙 사이즈가 테라바이트급으로 커지면 G1 GC조차도 압축(Compaction) 작업 시 발생하는 Stop-The-World(STW) 시간을 수백 밀리초 이내로 방어하기 어려워집니다. 금융 시스템의 초단타 매매나 대규모 실시간 스트리밍 처리처럼 ‘단 10ms의 지연’도 용납되지 않는 극한의 환경을 위해 등장한 것이 바로 차세대 초저지연(Ultra-Low Latency) 가비지 컬렉터인 ZGC와 Shenandoah GC입니다.
1. ZGC (Z Garbage Collector): 멈추지 않는 확장성
ZGC는 오라클(Oracle)이 주도하여 개발한 가비지 컬렉터로, Java 11에서 실험적으로 도입되어 Java 15부터 정식 기능으로 채택되었습니다. ZGC의 궁극적인 목표는 “힙 메모리 크기가 8MB이든 16TB이든 관계없이, Stop-The-World 시간을 10ms(최근 버전에서는 1ms) 이하로 유지하는 것”입니다.
- 컬러 포인터 (Colored Pointers): ZGC의 가장 핵심적인 기술입니다. 기존 GC들은 객체의 상태(마킹 여부 등)를 객체 자체의 헤더에 기록했습니다. 반면 ZGC는 객체를 가리키는 64비트 메모리 포인터(주소) 공간 중 몇 개의 비트(Bit)를 차용하여 객체의 상태 정보(색상)를 저장합니다. 이를 통해 메모리를 직접 조회하지 않고도 포인터만 보고 객체의 상태를 빠르게 파악할 수 있습니다.
- 로드 배리어 (Load Barrier): 애플리케이션 스레드가 힙 영역에 있는 객체를 참조(Load)할 때마다 중간에 개입하는 얇은 보호막입니다. GC가 살아있는 객체를 새로운 안전한 공간으로 이동(이사)시키고 있는 중이더라도, 로드 배리어가 애플리케이션 스레드에게 객체의 ‘새로운 주소’를 즉시 알려줍니다. 덕분에 애플리케이션 스레드를 멈추지 않고도(Concurrent) 안전하게 객체를 이동시킬 수 있습니다.
2. Shenandoah GC: 오픈 JDK의 저지연 승부수
Shenandoah(셰넌도어) GC는 레드햇(Red Hat)이 주도하여 개발했으며, ZGC와 마찬가지로 초대용량 힙에서 극단적으로 짧은 정지 시간을 보장하는 것을 목표로 합니다. Java 12에서 실험적으로 도입되어 Java 15부터 정식 채택되었습니다. (단, Oracle JDK에는 포함되지 않으며 OpenJDK 환경 등에서 사용 가능합니다.)
- 동시 압축 (Concurrent Compaction): Shenandoah GC의 최대 강점입니다. G1 GC는 살아있는 객체들을 다른 리전으로 모으는 압축 과정에서 반드시 Stop-The-World를 발생시켰습니다. 하지만 Shenandoah는 애플리케이션이 구동 중인 상태에서도 백그라운드에서 객체를 이동시키고 파편화를 해결합니다.
- 브룩스 포인터 (Brooks Pointers): Shenandoah가 동시 압축을 구현하는 핵심 기술입니다. 모든 객체에 자신(혹은 이동된 새로운 복사본)을 가리키는 포워딩 포인터(Forwarding Pointer)를 하나씩 추가합니다. 만약 객체가 이사 중이라면, 이 포인터가 새로운 주소를 가리키게 하여 애플리케이션 스레드가 길을 잃지 않고 정확한 데이터에 접근할 수 있도록 보장합니다.
3. 실무 도입 시 고려사항 (Trade-off)
ZGC와 Shenandoah GC는 모두 마법 같은 저지연 성능을 보여주지만, 세상에 공짜는 없습니다.
- 처리량(Throughput)의 희생: 두 GC 모두 애플리케이션 스레드를 멈추지 않기 위해 백그라운드에서 끊임없이 GC 스레드를 맹렬하게 돌립니다. 즉, CPU 자원을 GC가 상당히 많이 소모하게 됩니다.
- 선택 가이드: 따라서 전체적인 ‘작업 처리량’이 중요하다면 여전히 G1 GC나 Parallel GC가 유리합니다. 반면, CPU 자원을 더 투자해서라도 사용자가 느끼는 ‘순간적인 서버 응답 지연(렉)’을 완전히 제거해야 하는 서비스라면 ZGC나 Shenandoah GC 도입을 적극적으로 검토해야 합니다.
결론: GC 기술의 진화와 우리의 자세
과거에는 GC의 Stop-The-World 현상을 피할 수 없는 ‘자바의 고질병’으로 여겼습니다. 하지만 ZGC와 Shenandoah의 등장으로 이제 개발자는 튜닝의 고통에서 벗어나 애플리케이션 로직 자체에 더 집중할 수 있게 되었습니다. 최신 JDK 버전(17, 21 이상)을 도입하는 것만으로도 막대한 성능 향상 인프라를 무료로 얻게 되는 셈입니다.
지금까지 자바의 메모리 구조와 다양한 GC 알고리즘들을 이론적으로 살펴보았습니다. 다음 포스팅부터는 이론을 넘어 실전으로 들어갑니다. ‘GC 로그 분석을 통한 Java 애플리케이션 병목 현상 진단 방법’을 통해 서버에서 발생하는 실제 GC 로그를 읽고 문제를 추적하는 노하우를 공개하겠습니다.