Arena Allocators in C
C에서 아레나 할당자 구현하기
아레나 할당자(arena allocator)는 비슷한 수명을 가진 데이터를 큰 메모리 블록에 모아 관리하고, 사용이 끝나면 한꺼번에 비우는 방식입니다. 글은 C로 간단한 아레나를 구현하고 문자열 복사에 적용해, 개별 메모리 해제 부담을 줄이는 방법을 설명합니다.
- 주제
AI 요약
C에서는 보통 필요한 만큼 malloc으로 할당하고, 사용이 끝나면 free로 해제합니다. 하지만 해제를 빠뜨리면 메모리가 계속 쌓이고, 작은 할당과 해제를 자주 반복하면 비용도 커집니다. 함수가 메모리를 할당하는지 호출자가 알아보기 어려운 점도 문제입니다.
수명이 비슷한 메모리를 함께 관리합니다
아레나 할당자는 데이터의 수명을 기준으로 메모리를 묶습니다. 프로그램 전체에서 쓰는 데이터, 게임 프레임이나 HTTP 요청이 끝날 때까지 쓰는 데이터, 함수 실행 중에만 쓰는 데이터처럼 비슷한 시점에 해제할 메모리를 하나의 큰 블록에 넣습니다. 아레나에서 메모리를 할당할 때는 사용 위치를 가리키는 값을 앞으로 옮깁니다. 데이터가 더는 필요하지 않으면 블록 전체를 해제하거나, 사용 위치를 처음으로 돌려 같은 블록을 다시 씁니다.
C로 구현한 아레나
예제의 arena 구조체는 메모리 시작 주소인 data, 전체 크기인 size, 사용량인 used를 기록합니다. arena_create는 malloc으로 블록을 만들고 성공 여부와 함께 결과 구조체를 반환합니다. arena_alloc은 used를 바탕으로 다음 할당 위치를 계산하고, 요청한 크기가 남은 공간을 넘지 않는지 확인합니다. 코드는 할당 시작 위치를 8바이트 경계에 맞추며, 성공 여부와 포인터를 결과 구조체에 담아 돌려줍니다.
arena_realloc은 기존 메모리 영역을 늘리는 대신, 아레나 끝에 새 크기로 공간을 할당하고 기존 내용을 복사합니다. 이전 데이터는 개별 해제가 불가능하므로 아레나를 비울 때까지 남습니다. 이 구현은 할당 크기를 따로 기록하지 않아, 복사할 기존 크기를 호출자가 전달해야 합니다. arena_clear는 used를 0으로 되돌리고, arena_free는 아레나가 확보한 메모리를 해제합니다.
문자열 변환에 적용합니다
글은 문자열 뷰(string view)를 소유 문자열(owned string)로 바꾸는 예를 듭니다. 변환 함수는 아레나에 문자열 길이보다 1바이트 큰 공간을 할당하고, 내용을 복사한 뒤 끝에 NUL 문자를 넣습니다. 호출자가 어떤 아레나를 넘기느냐에 따라 문자열의 수명이 결정됩니다. 함수의 인자만 봐도 아레나 할당이 일어난다는 점이 드러나며, 문자열을 개별적으로 해제할 필요도 없습니다.
구현을 사용할 때 확인할 점
Lobsters 댓글은 코드가 C23 기능을 사용하면서 이를 설명하지 않았다고 지적합니다. [[nodiscard]] 속성과 속성 문법은 C23에 포함됐습니다. 또 코드에서 void *에 포인터 산술을 적용하는데, 이는 표준 C에서 허용되지 않으며 GCC가 확장 기능으로 받아들입니다.
원문: Eliasebner / 번역·요약: Trawling
Lobsters 반응
- @nickmonad — 컴퓨터공학 학위를 전부 마치는 동안 C를 아주 많이 다뤘는데도 아레나 할당자는 한 번도 배우지 못했습니다. 이렇게 분명히 유용한 기법인데 말입니다.
- @spc476 — 제시된 코드에는 문제가 있습니다. 작성자는 C23을 사용하면서도 이를 언급하지 않았습니다. [[nodiscard]] 속성은 C23 기능이고, 속성 문법 자체도 C23 기능입니다. 또 void *에 포인터 산술을 적용하는 부분도 발견했습니다. 제가 아는 어떤 C 표준에서도 허용하지 않지만 GCC는 컴파일러 확장으로 허용합니다.