개요

G1GC(Garbage-First Garbage Collector)는 자바 가상 머신(JVM)의 가비지 컬렉션 알고리즘 중 하나이다. 대규모 힙 메모리를 효율적으로 관리하고 가비지 컬렉션으로 인한 지연 시간을 최소화하기 위해 설계되었다. G1GC는 힙 메모리를 여러 리전(region)으로 나누어 관리하며, 가비지가 많은 리전을 우선적으로 수집하는 방식으로 동작한다.

주요 특징

메모리 분할
G1GC는 힙 메모리를 동일한 크기의 리전으로 나누어 관리한다. 각 리전은 독립적으로 수집되며, 전체 힙을 한 번에 처리하는 방식보다 효율적이다. 여러개의 Region들 중에서, 하나의 Region이 current allocation region으로 선택되며, 각각의 스레드들은 CAS operation을 통해서 Thread local buffer을 할당 받아 Allocation을 수행한다. 이떄 Region크기의 3/4를 넘는 큰 object allocation은 특별히 따로 Allocation되며 이러한 heap region들을 Humongous(육중한) region이라고 명명하였다.
Remembered Set
각각의 Region마다 Remembered set이라고 명명된 외부 Region에서 그 리전을 참조하고 있는 Reference을 추적하기 위한 Table이 존재한다. Remembered set (Rset)을 관리하기 위해서 Mutator thread (Application thread)는 reference참조시에 remebered set을 관리해야 한다. 관리를 위해서 Card table이 사용된다. Application이 write을 수행하면, write barrier를 통해서 그 포인터가 card table에 업데이트가 필요한지를 계산한다. 이때 Rset은 역참조로써, Region을 참고하고 있는 Card table을 기록하고 있다.
Evacuation Pauses & Concurrent Marking
G1GC는 가비지가 많을 것으로 예상되는 리전을 우선적으로 수집한다. 이를 통해 가비지 컬렉션의 효율성을 높이고 애플리케이션의 일시 정지 시간을 줄인다. Evacuation pauses단계에서는 Compaction을 통해서 Victim이 된 Region의 모든 Heap address를 다른 Region으로 옮긴다. 그후 Victim region들은 모두 Free된다. Evacuation단계를 모두 Serialize하는 것은 Pause time을 매우 크게 할 수도 있다. 따라서 Evacuation pause는 최대한 병령화 될 수 있도록 하였다. G1GC는 여러 스레드를 사용하여 가비지 컬렉션 작업을 Application thread와 함께 병렬로 수행한다. 이 단계에서 Rset이 사용되며, 이를 통해서 효율적으로 Concurrent하게 GC를 수행할 수 있도록 하였따.
Generational Garbage-First
G1GC의 G1의 의미이기도한 Garbage-First에 대한 설명은 원 논문에서는 Default로 사용되고 있지 않다고 나와있다. 이해하기론, Generational GC를 사용하게 되면 Young Region (e.g., Allocation region)이 Garbage를 포함할 확률이 높음으로, 우선순위로 GC의 대상이 된다.

G1GC의 설계 이유

  1. 메모리 단편화 감소: 고정 크기의 리전으로 힙을 나누어 관리함으로써 단편화를 줄인다.
  2. 수집 우선순위 설정: 리전별로 살아있는 데이터의 양을 기준으로 우선순위를 설정하여 가장 효과적인 리전부터 수집한다.
  3. 부분적인 힙 정리 가능: 전체 힙 대신 일부 리전만 선택적으로 수집하여 일시 정지 시간을 제어한다.

G1GC의 목표

G1GC의 핵심 목표는 Large memory footprint를 가지는 server프로그램에서도 예측 가능한 짧은 일시 정지 시간을 유지하는 것이다. 이를 위해 모든 단계는 설정된 목표 일시 정지 시간을 초과하지 않도록 설계되었다. 이는 대규모 애플리케이션에서 응답성과 성능의 균형을 유지하는 데 기여한다.

G1GC의 단계

Initial Mark

Initial Mark 단계는 Old 영역의 객체 중 GC 루트와 연결된 객체를 마킹하는 과정이다. 이 단계는 Stop-the-World(STW) 상태에서 수행된다. Eden 영역의 객체가 Young GC를 통해 이동할 때 함께 처리된다.

이유
초기 참조 그래프를 설정하여 이후 단계에서 마킹 작업을 이어가기 위한 기반을 마련하기 위함이다. 빠른 처리를 통해 일시 정지 시간을 최소화한다.

Concurrent Mark

Concurrent Mark 단계는 애플리케이션이 실행 중일 때 Old 영역의 객체를 스캔하여 살아있는 객체를 식별한다. 각 리전의 살아있는 데이터 양을 계산한다.

이유
애플리케이션 실행을 방해하지 않고 대부분의 마킹 작업을 처리하기 위함이다. 이 정보를 활용하여 우선적으로 수집할 리전을 결정한다.

Remark

Remark 단계는 Concurrent Mark 이후 참조 그래프의 업데이트를 반영하여 최종적으로 살아있는 객체를 확인하는 과정이다. 이 단계는 STW 상태에서 수행된다.

이유
정확한 데이터를 확보하여 효율적인 가비지 수집을 수행하기 위함이다.

Cleanup

Cleanup 단계는 가비지로 식별된 리전을 정리하고 수집 우선순위를 계산하는 단계이다. 이 정보는 Mixed GC 단계에서 활용된다.

이유
메모리 단편화를 줄이고 가장 효과적인 리전부터 수집하기 위한 준비를 하기 위함이다.

Young GC

Young GC는 Eden 영역이 가득 차면 트리거된다. 살아남은 객체는 Survivor 영역 또는 Old 영역으로 이동한다. 이 단계는 STW 상태에서 수행된다.

이유
Eden 영역은 주로 단명 객체가 위치하는 공간으로, 주기적으로 비워야 메모리 부족을 방지할 수 있다.

Mixed GC

Mixed GC는 Young 영역과 일부 Old 영역을 함께 수집하는 과정이다. 가비지가 많은 리전을 우선적으로 수집하며 병렬로 진행된다.

이유
Old 영역의 가비지를 주기적으로 정리하여 메모리 사용량을 줄이고 성능을 유지하기 위함이다.