GN⁺: 시스템 프로그래머를 위한 가비지 컬렉션 (2023)
(bitbashing.io)RCU 소개
- 운영 체제는 매일 가장 성능에 민감한 프로그램 중 하나임.
- 운영 체제는 항상 더 빠를 수 있으며, 커널과 드라이버 개발자들은 코드 최적화에 매진함.
- 운영 체제는 대규모 동시성을 필요로 하며, 사용자 공간 프로세스와 스레드를 스케줄링하고, 자체 스레드와 하드웨어와 상호 작용하는 인터럽트 핸들러를 가짐.
RCU의 작동 원리
- 자주 읽히지만 드물게 쓰이는 데이터(예: 현재 연결된 USB 장치)를 원자적으로 변경해야 할 때 RCU(Read, Copy, Update) 전략을 사용함.
- 데이터를 읽고, 복사하여 변경한 다음, 포인터를 새 버전으로 원자적으로 업데이트함.
- 이 방법은 사용하기 쉽고 대기 시간이 없으나 메모리 누수가 발생할 수 있음.
메모리 누수 문제 해결
- 메모리 누수를 방지하기 위해, 업데이트 함수 내에서 오래된 데이터를 삭제하는 대신, 현재 읽고 있는 리더가 없을 때 삭제하도록 연기할 수 있음.
- 리더가 데이터를 읽는 동안 작성자가 데이터 삭제를 기다리게 하여 안전하게 메모리를 관리함.
RCU의 실제 사용
- RCU는 리눅스에서 수만 번 사용되며, Facebook의 Folly C++ 라이브러리와 Rust의
crossbeam-epoch
에서도 사용됨. - RCU는 성능과 지연 시간 요구에 의해 동기화되며, 가비지 컬렉션과 유사한 메모리 관리 방식을 제공함.
가비지 컬렉션에 대한 오해
- 가비지 컬렉션이 수동 메모리 관리보다 느리다는 통념은 세부 사항을 살펴보면 빠르게 무너짐.
-
free()
함수는 무료가 아니며, 메모리 할당자는 내부적으로 많은 상태를 유지해야 함. - 현대의 가비지 컬렉션은 이동 및 세대별 최적화를 제공하여 높은 처리량과 캐시 성능을 제공함.
제어의 환상
- 개발자들은 때때로 실시간 시스템을 구축하고자 하지만, 실제로는 메모리 관리에 대한 완벽한 제어가 없음.
- 운영 체제는 메모리 할당에 대한 개발자의 의도를 추측할 뿐이며, 때로는 단순한 포인터 접근이 디스크 I/O로 변할 수 있음.
결론
- 모든 소프트웨어가 가비지 컬렉션에서 이득을 보는 것은 아니지만, 가비지 컬렉션은 유용한 도구이며, 시스템 프로그래머들 사이에서도 더 이상 두려워하지 않아야 함.
GN⁺의 의견
- RCU는 멀티스레딩 환경에서 데이터 일관성을 유지하면서 동시성을 높이는 효과적인 기법임. 이는 고성능 컴퓨팅이나 실시간 시스템에서 매우 중요한 요소임.
- 가비지 컬렉션에 대한 통념을 깨는 RCU의 예시는 개발자들에게 메모리 관리에 대한 새로운 관점을 제공함. 이는 특히 메모리 관리가 중요한 시스템 프로그래밍 분야에서 더욱 그러함.
- RCU와 유사한 기능을 제공하는 다른 프로젝트로는 Java의 ConcurrentLinkedQueue나 .NET의 ConcurrentBag 등이 있으며, 이들도 락-프리(lock-free) 데이터 구조를 제공함.
- RCU 기술을 도입할 때는 시스템의 요구 사항과 성능 목표를 고려해야 하며, 이 기술을 사용함으로써 얻는 이점과 잠재적인 비용을 이해해야 함.
- 이 기사는 개발자들이 메모리 관리와 동시성에 대해 더 깊이 이해하고, 기존의 가정을 재고하며, 새로운 솔루션을 탐색하는 데 도움이 될 수 있음.
Hacker News 의견
-
MPL과 MaPLe에 대한 혁신적인 병렬 가비지 컬렉션(GC) 기술을 확인하라는 제안
- POPL 2024에서 뛰어난 논문상과 ACM SIGPLAN 2023년 논문상을 수상함
- 주요 제안 사항은 다음과 같음:
- 증명 가능한 효율적인 병렬 가비지 컬렉션 기반의 'disentanglement'
- 증명 가능한 효율적인 자동 세분성 제어
-
RCU를 가비지 컬렉션의 동기로 사용하는 것은 흥미로움
- 쓰기 작업자로부터 마지막 읽기 작업자에게 메모리 해제 책임을 이전하는 것이 의미 있음
- 성능 향상을 위해 메모리 해제를 읽기 작업자가 아닌 전용 배치 프로세스로 이전하는 것을 고려해야 할 수도 있음
-
메모리 관리에 대한 일반적인 오해
- 프로그래머가 메모리 관리를 위한 최적의 일시 중지 시간을 알고 있다고 믿음
- 게임과 암호화폐 거래 프로그램에서는 프로그래머가 실제로 최적의 일시 중지 시간을 알고 있을 수 있음
-
RCU 사용 사례는 설득력이 있지만, 다른 상황에서의 가비지 컬렉션 경험은 좋지 않음
- 맞춤형 메모리 관리 솔루션이 최상의 성능을 제공할 수 있다는 주장으로 읽힘
-
free()
호출이 메모리를 OS에게 반환한다는 오해에 대한 논의
-
가비지 컬렉션을 사용하면 새로운 할당이 캐시가 아닌 RAM에서 이루어짐
- 성능에 큰 영향을 미칠 수 있음
- Julia 언어에서의 벤치마크 예시 제공
-
좋은 추적 가비지 컬렉션은 오래전에 수동 메모리 관리를 처리량 측면에서 능가함
- 최근에는 대부분의 애플리케이션에 대해 지연 시간이 수용 가능한 수준임
- 메모리 사용량이 주요 고려 사항임
-
가비지 컬렉션과 잘 어울리는 것 중 하나는 async/await
- Rust에서 async/await 사용은 메모리 관리와 결합하여 문제를 일으킴
-
RCU에 대한 동기 부여 후 일반적인 가비지 컬렉션에 대한 논의로 전환하는 것은 다소 놀라움
-
소프트웨어 개발 시 두 가지 경우를 고려함
- 핫 패스의 경우 맞춤형 할당자를 사용하고, 그 외의 경우에는 가비지 컬렉션이 편리함
-
RCU에서 일반적인 추적 가비지 컬렉션으로의 전환은 교묘한 전략으로 보임
- 수동 메모리 관리는 단순히 malloc/free 호출 이상의 것을 포함함
-
시스템 프로그래머가 언제 가비지 컬렉션될 수 있는지 식별하는 것이 어려움
-
Rust와 C++의 생명주기 관리 도구는 메모리 해제 자동화에 도움을 주지만, 복잡성을 단순화하지는 않음