Card Table 개요

Card Table은 객체 참조 관계를 효율적으로 관리하기 위해 사용하는 데이터 구조이다. 주로 Generational GC에서 세대 간 참조를 추적하는 데 사용된다.

Card Table의 역할

Generational GC의 효율성 보장
Generational GC는 Young 세대와 Old 세대 간 객체 참조를 관리해야 한다. Card Table은 Old 세대에서 Young 세대를 참조하는 객체를 효율적으로 추적하기 위해 사용된다.
Write Barrier와의 연계
객체 참조가 변경될 때마다 Write Barrier를 통해 Card Table에 해당 영역이 수정되었음을 기록한다. 이를 통해 GC는 Old 세대를 모두 스캔하지 않고, 수정된 영역만 스캔하도록 최적화된다.
최소화된 스캔 범위
Card Table은 “Dirty Card”라는 상태를 통해 참조가 변경된 영역만 스캔하도록 돕는다. 이는 GC 작업량을 줄이는 데 기여한다.

Card Table의 구성 및 동작 원리

구성

  • 힙 메모리는 여러 카드(Card)로 나뉜다. 각 카드의 크기는 고정된 단위(예: 512바이트, 1KB 등)이다.
  • Card Table은 카드들의 상태를 나타내는 배열로 구성된다.
  • 각 배열 엔트리는 해당 카드의 상태를 나타낸다. (예: 0은 참조 변경이 없음을, 1은 참조 변경이 있음을 나타낸다.)

Write Barrier

  • 객체의 필드가 갱신될 때 Write Barrier가 호출된다.
  • Write Barrier는 Card Table을 갱신하여 해당 카드가 Dirty 상태임을 기록한다.

GC 단계에서의 사용

  • GC는 Card Table에서 Dirty 상태의 카드만 스캔한다.
  • Dirty 상태의 카드 내에서 Young 세대로의 참조를 추적하고, 해당 객체들을 마킹한다.
  • 이를 통해 Old 세대 전체를 스캔하지 않아도 된다.

Card Table의 장점

성능 최적화
Old 세대 전체를 스캔하지 않아도 Dirty Card만 스캔하여 참조 관계를 확인한다. 이는 GC 성능을 크게 향상시킨다.
세대 간 참조 추적의 간소화
Dirty Card 기반으로 참조를 탐지하므로, 세대 간 참조 관리가 단순화된다.
효율적인 메모리 사용
Card Table은 힙 메모리 크기에 비해 매우 적은 메모리를 사용한다.

Card Table의 단점

False Positives
한 카드 내의 일부 객체만 참조가 변경되더라도 카드 전체가 Dirty로 표시될 수 있다. 이는 불필요한 스캔을 초래한다.
Write Barrier 오버헤드
객체 참조 변경 시 Write Barrier가 실행되므로 약간의 성능 오버헤드가 발생한다.
카드 크기 설정의 트레이드오프
카드 크기가 작으면 Card Table의 크기가 커지고 Write Barrier의 부하가 늘어난다. 카드 크기가 크면 False Positives가 증가한다.

결론

Card Table은 Generational GC에서 필수적인 데이터 구조로, 세대 간 참조를 효율적으로 관리하고 GC의 성능을 높이는 데 중요한 역할을 한다. 이를 통해 Young 세대의 객체를 빠르고 효율적으로 수집할 수 있으며, 메모리 사용량과 처리 시간을 최적화할 수 있다. 그러나 False Positives와 Write Barrier 오버헤드와 같은 단점도 존재하므로 시스템에 따라 적절히 조정해야 한다.