자바 언어·플랫폼 용어 사전
GC·JITG1 · Shenandoah · Region · 동시 수집기 · 컬러 포인터

ZGC

정지 시간을 힙 크기와 무관하게 유지하는 동시 수집기. G1과의 선택 기준.

정지 시간을 힙 크기와 무관하게 밀리초 수준으로 유지하는 동시 수집기.

  • G1 — 기본값. 힙을 Region 으로 나누고, 쓰레기가 많은 Region 부터 고른다

    • (Garbage-First) 목표 정지 시간을 주면 그에 맞춰 수집량을 조절
    • 정지 시간 수십~수백 ms
  • ZGC — 이동(복사)까지 애플리케이션과 동시에 수행한다

    • 정지 시간 1ms 미만, 힙이 수 TB 여도 유지된다
  • Shenandoah — 목표가 비슷하다 (Red Hat 주도)

어떻게 이동을 동시에 하나

객체를 옮기는 동안 애플리케이션이 옛 주소를 읽으면 안 된다

ZGC 는 참조 안의 사용하지 않는 비트에 상태를 새긴다 (컬러 포인터) + 읽기 배리어: 참조를 읽을 때마다 "이미 옮겨졌는가" 를 검사하고

  • 옮겨졌으면 새 주소로 고쳐 준다 (self-healing)

  • STW 는 루트 스캔 같은 아주 짧은 구간만 남는다

공짜가 아니다

읽기 배리어 비용 → 처리량이 G1 대비 몇 % 떨어질 수 있다 메모리 사용량이 더 크다

즉 지연 시간을 처리량·메모리와 맞바꾸는 것이다

실무 선택 기준

  • 힙 8GB 이하 · 일반 웹 서비스 G1 (기본값으로 충분)
  • 지연 시간 SLA 가 엄격 (p99 중요) — ZGC
  • 힙 32GB 이상 · 정지가 곧 사고 ZGC
  • 처리량이 최우선 · 배치 — Parallel GC
  • 짧게 살고 끝나는 프로세스 — Serial / Epsilon

"기본값으로 시작하고, 정지 시간이 실제 문제일 때 바꾼다" 가 순서다 측정 없이 GC 를 바꾸는 것은 대체로 손해다

압축 참조 경계

힙이 32GB를 넘으면 압축 참조가 꺼져 참조가 4→8바이트가 된다. 31GB와 33GB의 실효 용량이 역전될 수 있어, 힙 증설 시 이 경계를 반드시 확인한다.

배리어의 위치가 설계를 가른다

  • G1 — 쓰기 배리어 중심 — 참조를 '쓸 때' 카드/큐를 갱신한다
    • 읽기가 잦은 워크로드에 유리
  • ZGC — 읽기 배리어 중심 — 참조를 '읽을 때' 색을 검사하고 고친다
    • 이동을 동시에 하려면 읽는 쪽을 잡아야 하기 때문이다
  • Shenandoah — 브룩스 포인터(간접 참조) → 이후 로드 참조 배리어로 전환

"어느 시점에 비용을 낼 것인가" 의 선택이고, 그래서 워크로드에 따라 승패가 갈린다

컨테이너에서 반드시 확인할 것

JVM 은 컨테이너 메모리 limit 을 인식한다 (Java 10+, UseContainerSupport) -XX:MaxRAMPercentage=75 물리 대신 limit 기준 비율로 힙 결정 -Xmx 를 직접 주면 limit 변경 시 따라가지 않는다

주의: 힙 밖에도 메모리가 든다

  • 메타스페이스 · 코드 캐시 · 스레드 스택 · DirectByteBuffer · GC 자체 구조
  • 힙을 limit 의 100% 로 잡으면 컨테이너가 OOMKill 된다
    • (JVM 의 OutOfMemoryError 가 아니라 커널이 죽인다 — 로그도 안 남는다)

면접 함정

  • "ZGC는 STW가 아예 없다" → 매우 짧은 구간이 남는다.
  • "최신 GC가 항상 낫다" → 처리량은 오히려 떨어질 수 있다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — GC·JIT는 무대 뒤에서 — 내부와 실무 튜닝