프로그래밍 언어 Gleam의 코드 포매터가 3년 묵은 성능 문제를 Rust의 '아레나(arena) 할당' 기법을 도입하여 성공적으로 해결했습니다. 이 개선으로 포매터의 핵심 기능인 프리티 프린터(pretty printer) 실행 시간이 13ms에서 9.8ms로 24% 빨라졌으며, 전체 코드 포맷팅 시간도 13% 단축되고 최대 메모리 사용량은 약 10% 감소했습니다. 이는 컴파일러 및 개발 도구 분야에서 흔히 발생하는 재귀적 데이터 구조의 성능 병목 현상을 효과적으로 해결한 사례입니다.
Gleam 포매터는 코드를 출력하고 줄바꿈을 처리하기 위해 재귀적인 문서(Document) 자료구조를 사용합니다. 이 구조는 문자열, 줄바꿈, 그룹화, 들여쓰기 등 다양한 요소로 구성되며, 특히 다른 문서를 내부에 포함하는 Nest 같은 변형은 기존에 `Box<Self>`를 사용하여 중첩 문서마다 힙(heap)에 개별 할당을 수행했습니다. 이러한 반복적인 개별 힙 할당이 성능 저하의 주된 원인이었으며, 이를 해결하기 위해 `Box<Self>`를 아레나에 저장된 `&'doc Self` 참조로 교체하는 방식이 채택되었습니다. `typed_arena` 크레이트를 활용하여 모든 문서 데이터를 하나의 아레나에 할당하고, Rust의 수명(lifetime) 검사기(borrow checker)를 통해 아레나가 제거된 후 잘못된 참조가 발생하지 않도록 안전성을 확보했습니다.
아레나 할당은 단순히 참조를 사용하는 것을 넘어, 언어 키워드나 반복되는 쉼표와 같은 작은 문서들을 한 번만 할당하고 재사용하는 캐싱(caching) 효과도 가져왔습니다. 수백 개의 작은 문서들이 매번 새로 할당되는 대신, 한 번만 생성되어 효율적으로 관리된 것입니다. 비록 아레나 API 자체는 단순하지만, 기존 코드베이스에 아레나 인수를 전달하고 할당 방식을 변경하는 대규모 수작업(약 +2963/-1032 라인 변경)이 필요했습니다. 하지만 이러한 노력 덕분에 속도와 메모리 사용량이라는 두 마리 토끼를 모두 잡을 수 있었습니다.
이번 Gleam 포매터의 성능 개선은 컴파일러, 린터(linter), 코드 포매터와 같은 개발 도구에서 재귀적 데이터 구조를 다룰 때 아레나 할당이 얼마나 강력한 해결책이 될 수 있는지를 보여줍니다. 특히 Rust와 같이 메모리 안전성을 중요시하는 언어에서 아레나를 활용하면 성능 최적화와 동시에 안전한 코드 작성을 유지할 수 있습니다. 이러한 접근 방식은 다른 컴파일러 프로젝트나 코드 분석 도구에서도 유사한 성능 문제를 해결하는 데 영감을 줄 수 있으며, 개발 생태계 전반의 효율성 향상에 기여할 것으로 기대됩니다.