본문 바로가기
language/java

ZGC (Z Garbage Collector) - 초저지연 GC의 원리

by 죄니안죄니 2026. 6. 29.
반응형

ZGC (Z Garbage Collector) - 초저지연 GC의 원리

Java GC를 이야기하면 항상 등장하는 문장이 있다.

"ZGC는 Pause Time이 1ms 이하래."

이 말은 대부분 사실이다.

하지만 많은 개발자가

"그럼 G1보다 무조건 좋은 GC 아닌가요?"

라고 생각한다.

그건 아니다.

GC는

"얼마나 빠른가?"

보다

"어떤 환경에서 가장 적합한가?"

가 훨씬 중요하다.

이번 글에서는

  • ZGC가 등장한 이유
  • G1과 근본적인 차이
  • Colored Pointer
  • Load Barrier
  • Concurrent Relocation
  • Pause Time이 짧은 이유
  • 실무에서 언제 사용하는가

까지 알아본다.


왜 ZGC가 등장했을까?

G1도 상당히 좋은 GC다.

하지만 Heap이 계속 커지면 문제가 생긴다.

예를 들어

Heap

256GB
 

또는

Heap

1TB
 

이런 환경에서는

아무리 Region으로 나눠도

Mark

Relocation

Reference Update

등의 작업이 점점 부담된다.


대규모 금융 시스템

실시간 광고 플랫폼

대용량 캐시 서버

AI 플랫폼

같은 서비스는

Heap이 수백 GB까지 커질 수 있다.


이런 환경에서

수십 ms의 Pause도

문제가 될 수 있다.

그래서 등장한 것이

ZGC
 

이다.


ZGC의 목표

G1의 목표

Pause Time

약 200ms
 

ZGC의 목표

Pause Time

1ms 이하
 

Heap이

4GB

64GB

512GB

1TB
 

가 되어도

Pause Time을 거의 일정하게 유지하는 것이 목표다.


G1과 가장 큰 차이

G1도

Concurrent Marking을 한다.

하지만

일부 작업은

Stop-The-World가 필요하다.


반면

ZGC는

거의 모든 작업을

애플리케이션과 동시에 수행한다.

Application

↓

GC

↓

동시에 실행
 

그래서

Pause가 매우 짧다.


기존 GC의 문제

예를 들어

객체 이동이 필요하다.

기존 GC는

객체 이동

↓

모든 참조 수정

↓

재시작
 

이 필요하다.


Heap이 클수록

참조 수정 시간이 길어진다.


ZGC는

이 과정을 다르게 처리한다.


Colored Pointer

ZGC의 핵심 기술

일반적인 객체 참조

0x12345678
 

메모리 주소만 가진다.


ZGC는

참조 자체에

메타데이터를 넣는다.

개념적으로는

주소

+

GC 상태 정보
 

를 가진다.

이를

Colored Pointer
 

라고 한다.


예를 들어

100101010101...
 

비트 일부는

객체 주소
 

나머지는

Mark 여부

Relocation 여부

Remapped 여부
 

같은 상태를 저장한다.


객체 자체가 아니라

참조가

현재 상태를 알고 있다.


왜 이렇게 할까?

기존 GC는

객체가 이동하면

모든 참조를 찾아야 한다.

객체 이동

↓

참조 전부 수정
 

ZGC는

참조를 읽는 순간

자동으로

최신 위치를 확인한다.


참조 수정

↓

나중에

필요할 때
 

수행한다.


Load Barrier

이것이 ZGC의 핵심이다.

객체를 읽을 때마다

특수한 Barrier가 실행된다.

예를 들어

 
user.getName();
 

실제로는

개념적으로

Load Barrier

↓

주소 확인

↓

필요하면 최신 주소 변경

↓

객체 접근
 

이 된다.


객체를 읽는 순간

자동으로

올바른 객체를 찾아간다.


그래서

GC가

모든 참조를

한 번에 수정할 필요가 없다.


Concurrent Relocation

기존 GC

객체 이동

↓

애플리케이션 정지

↓

참조 수정

↓

재시작
 

ZGC

객체 이동

↓

애플리케이션 계속 실행

↓

Barrier가

최신 주소 제공
 

객체 이동도

동시에 수행한다.


왜 Pause가 짧을까?

대부분의 작업을

Concurrent로 수행하기 때문이다.

예를 들어

Mark

Reference Update

Relocation
 

전부

백그라운드에서 수행된다.


Stop-The-World는

정말 최소한의 작업만 한다.

그래서

Pause가

1ms 이하까지 내려간다.


단점

CPU 사용량 증가

Concurrent 작업이 많다.

백그라운드 스레드가

계속 동작한다.


작은 Heap에서는 효과가 적다

Heap

512MB
 

정도라면

G1과 큰 차이를 느끼기 어렵다.


구현이 복잡하다

Colored Pointer

Barrier

Concurrent Relocation

등이 추가된다.


실무에서는 언제 사용할까?

다음과 같은 환경에서 많이 사용된다.

  • 초대형 Heap
  • 초저지연 서비스
  • 금융 시스템
  • 게임 서버
  • 실시간 광고 플랫폼
  • AI 추론 서버

반대로

일반적인

Spring Boot

REST API

관리 시스템

전자결재

쇼핑몰

정도라면

G1으로 충분하다.


G1 vs ZGC

항목G1ZGC
기본 GC(Java 17) O X
Pause 수십~수백 ms 보통 1ms 이하
Heap 중대형 초대형
CPU 보통 높음
처리량 높음 약간 낮을 수 있음
실무 사용 가장 많음 특정 분야 중심

Java 버전별 변화

초기 ZGC는

Linux만 지원했다.

이후

Java 15부터

정식 기능으로 자리 잡았고

현재는

Linux

Windows

macOS

모두 지원한다.

Java 17 이상에서는

실무에서도 충분히 사용할 수 있는 수준으로 안정화되었다.


ZGC 사용 옵션

 
-XX:+UseZGC
 

옵션 설명

  • -XX:+UseZGC
    • ZGC를 활성화한다.

Heap 설정

 
-Xms16g
-Xmx16g
 

옵션 설명

  • -Xms16g
    • JVM 시작 Heap을 16GB로 설정한다.
  • -Xmx16g
    • Heap 최대 크기를 16GB로 설정한다.

실무에서는 ZGC도 -Xms와 -Xmx를 동일하게 맞추는 경우가 많다.


G1보다 무조건 좋은가?

아니다.

예를 들어

쇼핑몰 API 서버

Heap

2GB
 

응답 시간

50ms
 

이 환경에서

ZGC를 사용해도

사용자는 거의 차이를 느끼지 못한다.

오히려

CPU 사용량만 증가할 수도 있다.


반대로

Heap

512GB
 

실시간 거래 시스템

Pause 20ms도 허용되지 않는 환경

이라면

ZGC가 매우 강력한 선택이 된다.


GC 선택 기준

실무에서는 보통 다음 기준으로 선택한다.

일반 웹 서비스

↓

G1
 

초대형 Heap

+

초저지연

↓

ZGC
 

배치 작업

↓

Parallel GC
 

GC는

최신 기술을 선택하는 것이 아니라

서비스 특성에 맞게 선택하는 것이 중요하다.


지금까지의 연결

객체 생성

↓

Young Generation

↓

Minor GC

↓

Promotion

↓

Old Generation

↓

G1

↓

ZGC
 

GC는 계속 발전해 왔다.

발전 방향은

"더 적게 멈추는 것" 이다.


정리

ZGC는

Heap 크기와 관계없이 매우 짧은 Pause Time을 유지하는 것을 목표로 설계된 GC 다.

핵심 기술은

Colored Pointer

↓

Load Barrier

↓

Concurrent Relocation
 

이다.

덕분에 객체 이동과 참조 갱신을 대부분 애플리케이션 실행과 동시에 수행할 수 있다.

하지만 모든 서비스에 ZGC가 정답은 아니다.

대부분의 Spring Boot 기반 웹 서비스에서는 G1 GC가 여전히 가장 현실적인 선택이며,

ZGC는 초대형 Heap과 초저지연이 반드시 필요한 환경에서 진가를 발휘한다.


다음 글

다음 글에서는 문자열 처리 최적화(String Performance Optimization) 를 다룬다.

왜 String은 immutable로 설계되었는지, StringBuilder, StringBuffer, StringConcatFactory, 컴파일러 최적화, intern(), 문자열 풀(String Pool)까지 실제 JVM이 문자열을 어떻게 최적화하는지 깊이 있게 살펴본다.

반응형

댓글