Ruby의 동적 메모리 관리는 힙(Heap) 내의 힙 페이지(Heap Page)와 슬롯(Slot) 단위로 이루어지며, 대부분의 Ruby 객체는 C 언어의 RVALUE
타입으로 관리됩니다. GC의 기본 아이디어는 참조되지 않는 객체를 찾아 메모리를 회수하는 ‘Mark-and-Sweep’ 방식입니다. Ruby의 GC는 효율성을 위해 ‘세대별 GC’를 도입했는데, 이는 새로 할당된 객체(Young Generation)와 오래된 객체(Old Generation)를 구분하여 Minor GC(Young Generation만 대상)와 Major GC(모든 객체 대상)를 수행합니다. 이 과정에서 Old Generation 객체가 Young Generation 객체를 참조하는 경우, Minor GC가 이 참조를 놓칠 수 있어 살아있는 객체가 잘못 회수될 위험이 있습니다. 이를 방지하기 위해 사용되는 것이 바로 Write Barrier입니다. Write Barrier는 Old Generation에서 Young Generation으로의 참조가 발생할 때 이를 ‘Remembered Set’에 기록하여 Minor GC가 해당 참조를 고려하도록 합니다. 또한, GC 처리 중 프로그램 실행을 짧게 중단시키는 ‘Incremental Marking’에서도 참조 변경을 감지하기 위해 Write Barrier가 활용됩니다. Ruby는 일부 unprotected
객체에 대해서는 Write Barrier 없이도 GC가 작동하도록 설계되어 있지만, protected
객체는 Write Barrier가 완벽하게 삽입되어야 합니다.
Ruby C 확장은 C 언어로 Ruby를 조작하거나 C 코드를 Ruby에서 활용할 수 있도록 하는 강력한 메커니즘입니다. C 확장에서는 Ruby 객체가 VALUE
타입으로 다루어지며, 특히 C 데이터 구조를 Ruby 객체로 래핑할 때 사용되는 TypedData
(T_DATA
) 객체가 중요합니다. TypedData
객체가 다른 Ruby 객체에 대한 참조를 포함하는 경우, 해당 객체를 protected
로 만들기 위해 Write Barrier를 반드시 삽입해야 합니다. 그렇지 않으면 GC가 오작동할 수 있습니다. Write Barrier는 주로 RB_OBJ_WRITE()
또는 RB_OBJ_WB()
매크로를 통해 호출됩니다.
WBCheck 도구는 이러한 Write Barrier의 수동 삽입 문제를 해결하기 위해 개발되었습니다. 이 도구는 C 확장 코드에 대한 정적 분석을 수행하여 Write Barrier가 필요한 위치를 자동으로 식별하고, 필요한 경우 직접 삽입합니다. 분석 과정은 다음과 같습니다. 첫째, GCC의 -E
옵션을 사용하여 C 코드 내의 매크로와 디렉티브를 전처리하여 정적 분석의 방해 요소를 제거합니다. 둘째, 오픈 소스 구문 분석 라이브러리인 Tree-sitter와 C99 문법을 사용하여 전처리된 코드를 구문 트리(Abstract Syntax Tree, AST)로 변환합니다. 셋째, 생성된 구문 트리를 두 단계에 걸쳐 분석합니다. 첫 번째 단계에서는 전역 변수, 구조체/공용체 정의, 함수 시그니처 등 표면적인 정보를 수집합니다. 두 번째 단계에서는 함수 본문을 깊이 탐색하여 TypedData
객체의 C 구조체 포인터와 Write Barrier가 필요한 참조 변경(대입, 함수 호출 인자 전달 등)이 발생하는 위치를 식별합니다. 이 과정에서 변수, 구조체 필드 등을 CVar
클래스의 인스턴스로 관리하고, 스코프별로 해시맵을 사용하여 지역 변수를 추적합니다. 특히 RB_CHECK_TYPEDDATA()
호출을 감지하여 TypedData
포인터를 추적하고, 대입이나 memcpy
와 같은 참조 변경 연산을 분석합니다.
WBCheck는 Date, JSON, StringIO 라이브러리의 C 확장 코드를 대상으로 테스트되었습니다. 대부분의 필요한 Write Barrier 삽입 위치를 성공적으로 감지했으나, stringio.c
의 한 곳을 제외하고는 모두 검출했습니다. 또한, 불필요한 Write Barrier 삽입(예: 초기화 중인 Young Generation 객체에 대한 참조 변경)을 줄이는 개선이 필요함을 확인했습니다. 이 도구는 아직 실험 단계이며, 전처리 자동화, 배열/구조체 필드 내의 포인터 처리, strcpy
와 같은 다른 표준 라이브러리 함수 지원 등 개선할 점이 많습니다. 마지막으로, 라이스의 정리(Rice’s Theorem)에 따라 임의의 비자명한 프로그램 속성을 정적 분석만으로 완벽하게 결정하는 것은 불가능하므로, 100%의 정확도 달성은 어려울 수 있음을 명시합니다.