Ruby 3.4의 모듈형 가비지 컬렉터 (Modular GC)

[EN] Modular Garbage Collectors in Ruby / Peter Zhu @peterzhu2118

작성자
RubyKaigi
발행일
2025년 05월 27일

핵심 요약

  • 1 Ruby 3.4에 도입된 실험적 기능인 모듈형 가비지 컬렉터(Modular GC)는 사용자가 요구사항에 맞춰 다양한 GC 구현체를 선택할 수 있도록 하여 성능 및 메모리 효율성을 향상시키는 것을 목표로 합니다.
  • 2 기존 Ruby의 Mark-Sweep-Compact GC는 단순하고 안정적이지만, 참조 카운팅, 세미-스페이스 복사, 병렬 처리, 동적 슬롯 크기 등 고급 GC 알고리즘의 유연성이 부족합니다.
  • 3 MMTK(Memory Management Toolkit)는 모듈형 GC API를 활용하여 Ruby에 통합된 최초의 외부 GC 구현체로, 다양한 GC 알고리즘과 병렬 처리 기능을 제공하여 Ruby의 GC 성능 개선을 위한 로드맵을 제시합니다.

도입

본 발표는 Ruby 코어 팀원이자 Shopify 선임 개발자인 Peter가 Ruby 3.4의 실험적 기능인 모듈형 가비지 컬렉터(Modular GC)에 대해 설명합니다. 기존 Ruby의 Mark-Sweep-Compact GC의 작동 방식과 그 한계를 짚어보고, 이러한 제약을 극복하기 위해 도입된 모듈형 GC의 필요성과 구현 배경을 다룹니다. 궁극적으로 Ruby 사용자가 특정 워크로드에 최적화된 가비지 컬렉터 구현체를 선택할 수 있도록 하는 유연성을 제공하는 것이 목표입니다.

Ruby의 기존 가비지 컬렉터(GC)

Ruby는 Mark-Sweep-Compact 알고리즘을 사용하는 GC를 채택하고 있습니다. 이 GC는 객체 할당, 생존/소멸 객체 판별, 그리고 소멸 객체 회수의 세 가지 주요 역할을 수행합니다. * Mark 단계: 루트 객체(전역 변수, 상수 등)에서 시작하여 참조되는 모든 객체를 추적하여 ‘살아있는(alive)’ 객체로 표시합니다. * Sweep 단계: Mark 단계에서 살아있는 것으로 표시되지 않은 객체들을 ‘소멸(dead)’ 객체로 간주하고 메모리를 회수합니다. 이 과정에서 파일 디스크립터 닫기, 파이널라이저 실행 등 객체에 할당된 추가 리소스도 정리합니다. * Compact 단계 (선택 사항): 메모리 단편화(fragmentation)를 줄이기 위해 살아있는 객체들을 힙의 한쪽 끝으로 이동시킵니다. Ruby는 이를 위해 Two-finger 알고리즘을 사용합니다. 이러한 방식은 구현이 간단하고 이해하기 쉬우며 안정적이지만, 성능 최적화를 위한 고급 GC 알고리즘을 적용하는 데는 한계가 있습니다.

기존 GC의 한계와 대안 알고리즘

Ruby의 기존 GC는 지난 30년간 개선되어 왔지만, 다음과 같은 기능들이 부족합니다. * 참조 카운팅(Reference Counting): 객체 참조 수를 추적하여 참조가 0이 되면 즉시 회수하는 방식입니다. Ruby의 write barrier 구현이 불완전하여 현재는 적용하기 어렵습니다. * 세미-스페이스 복사(Semi-Space Copying): 메모리를 두 영역으로 나누어 살아있는 객체만 다른 영역으로 복사하여 단편화를 제거합니다. 메모리 사용량이 두 배로 늘어나고, Ruby가 요구하는 객체 고정(pinning)을 지원하지 못해 적용이 불가능합니다. * IMMIX: Mark-Sweep과 Semi-Space Copying의 아이디어를 결합한 알고리즘입니다. 힙을 블록으로 나누고, 단편화가 심한 블록의 살아있는 객체만 이동시키며, 객체 고정을 지원하여 Ruby에 적용 가능성이 높습니다. * 병렬 처리(Parallelism): 현재 Ruby GC는 단일 스레드로 동작하여 멀티 코어 CPU의 이점을 활용하지 못하며, Ractor 사용 시 병목 현상의 원인이 됩니다. 병렬 GC는 성능 향상에 필수적입니다. * 동적 슬롯 크기(Dynamic Slot Sizes): Ruby 3.2에서 가변 폭 할당(variable with allocation)을 도입하여 메모리 효율성을 개선했지만, 40바이트의 거듭제곱 형태인 5가지 고정된 슬롯 크기(40, 80, 160, 320, 640바이트)로 제한됩니다. 완전한 동적 슬롯 크기 지원은 더 큰 성능 및 메모리 효율성 개선을 가져올 수 있습니다.

모듈형 가비지 컬렉터 (Modular GC)

이러한 한계를 극복하기 위해 Ruby는 기존 GC를 대체하는 대신, 사용자가 필요에 따라 GC 구현체를 전환할 수 있는 모듈형 가비지 컬렉터를 도입했습니다. * 도입 배경: 모든 워크로드에 맞는 ‘만능’ GC는 없으며, 기존 GC의 안정성을 유지하면서 새로운 알고리즘의 유연성을 확보하기 위함입니다. * Ruby 3.4의 실험적 기능: GC 구현을 위한 API와 Ruby에 로드하는 메커니즘을 제공합니다. * 구조 변화: 기존 GC.c 파일을 VM 인터페이스(GC.c)와 실제 Mark-Sweep GC 구현(gc/default.c)으로 분리했습니다. GC 구현체는 공유 라이브러리 형태로 Ruby에 로드됩니다. * Modular GC API: GC 구현체가 반드시 구현해야 하는 약 60개의 함수(부팅, 종료, GC 주기 실행, 객체 할당, 마킹, 고정, write barrier 등)와 Ruby VM이 GC 구현체에 제공하는 함수(VM 잠금/해제, Ractor 중지, 객체 참조 순회, 객체 정리 등)로 구성됩니다.

MMTK (Memory Management Toolkit) 통합

MMTK는 Modular GC API를 활용하여 Ruby에 통합된 최초의 외부 GC 구현체입니다. * MMTK란?: Rust로 작성된 언어 독립적인 가비지 컬렉터 프레임워크로, 다양한 GC 알고리즘(Plans)을 제공합니다. Java(Open JDK), Julia, V8(JavaScript) 등 여러 언어에 통합되어 있습니다. * MMTK의 주요 기능: * 다양한 GC 알고리즘: No GC, Mark-Sweep, Mark-Compact, Semi-Space Copying, IMMIX, LXR (Latency Critical Immix with Reference Counting) 등을 지원합니다. LXR은 참조 카운팅과 IMMIX를 결합하여 낮은 지연 시간과 높은 성능을 제공합니다. * 병렬 처리: Work Packet 개념을 사용하여 GC 작업을 여러 스레드에서 병렬로 처리할 수 있도록 설계되었습니다. * MMTK와 Ruby의 통합: * MMTK 팀이 2020년부터 Ruby 포크를 통해 구현 작업을 진행해왔습니다. * Modular GC 도입 후, 기존 MMTK 구현의 아이디어를 Modular GC API 위로 포팅하는 작업이 진행 중입니다. 현재 No GC, Mark-Sweep, Non-moving IMMIX가 구현되었습니다. * MMTK 바인딩은 C 레이어(Modular GC API와 상호작용)와 Rust 레이어(MMTK 코어와 상호작용)로 구성됩니다. * 향후 로드맵: 현재 MMTK 기반 Ruby GC는 Ruby 기본 GC보다 느리지만, Moving Plan 지원, 세대별 GC(Generational GC) 지원(Sticky IMMIX 등), Work Packet 세분화를 통한 병렬 처리 극대화, 그리고 GC 내부의 스레드 안전성 확보를 통해 성능을 크게 개선할 계획입니다.

결론

본 발표는 Ruby의 Mark-Sweep-Compact GC의 기본 원리를 설명하고, 이 GC가 가진 한계점과 이를 극복하기 위한 다양한 GC 알고리즘의 필요성을 제시했습니다. 핵심적으로 Ruby 3.4에 도입된 실험적 기능인 모듈형 가비지 컬렉터(Modular GC)의 설계와 API 구조를 소개하며, 이를 통해 Ruby VM이 GC 구현체와 어떻게 상호작용하는지 설명했습니다. 또한, Modular GC API를 활용한 최초의 외부 GC 구현체인 MMTK(Memory Management Toolkit)의 통합 현황과 MMTK가 제공하는 고급 GC 기능 및 병렬 처리 로드맵을 다루었습니다. Modular GC는 아직 실험 단계이지만, 사용자 요구사항에 맞는 최적의 GC를 선택할 수 있는 유연성을 제공하여 Ruby의 성능과 메모리 효율성을 한 단계 더 끌어올릴 잠재력을 가지고 있습니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!