Rust, 메모리 레이아웃은 어떻게 관리될까?

by DD
5개월 전
조회수 3

C/C++와 달리 Rust는 컴파일러가 필드 순서를 재정렬하여 메모리 패딩을 최소화하는 repr(Rust)를 기본으로 사용함.

repr(C)를 통해 C 호환 레이아웃을 지원하며, FFI 및 특정 메모리 구조에 대한 안정성을 보장하지만, 패딩으로 인한 공간 낭비 가능성이 존재함.

DST(Dynamically Sized Types), 즉 런타임에 크기가 결정되는 타입(슬라이스, 스트링 슬라이스, 트레이트 객체)은 와이드 포인터를 사용하여 포인터와 길이를 함께 저장하여 C의 배열 문제를 해결함.

Rust의 메모리 레이아웃 최적화 전략

Rust는 필드 재정렬을 통해 메모리 패딩을 최소화하여 메모리 사용량을 줄인다. 구체적으로, 컴파일러는 필드의 크기와 정렬 요구사항을 분석하여 최적의 순서를 결정한다. 따라서, 개발자는 별도의 설정을 하지 않아도 성능 향상을 기대할 수 있다. 반면, 필드 오프셋에 대한 예측이 어려워, 특정 메모리 주소에 직접 접근하는 코드는 주의해야 한다.

DST(Dynamically Sized Types)의 구현과 트레이드오프

Rust의 DST는 런타임에 크기가 결정되는 타입을 지원하며, 와이드 포인터를 사용하여 포인터와 추가 정보를 함께 저장한다. 구체적으로, 슬라이스(`[T]`)는 데이터 포인터와 길이를, 트레이트 객체(`dyn Trait`)는 데이터 포인터와 vtable 포인터를 갖는다. 따라서, C의 배열과 달리 버퍼 오버플로우 문제를 방지할 수 있지만, 메모리 접근에 추가적인 비용이 발생한다.

FFI(Foreign Function Interface)와 repr(C)의 중요성

Rust에서 C 코드와 상호 작용하기 위해 repr(C)를 사용하여 C 호환 레이아웃을 지정한다. 구체적으로, 필드 순서를 C와 동일하게 유지하고, 패딩을 C의 규칙에 따라 삽입한다. 따라서, FFI를 통해 C 라이브러리를 안전하게 사용할 수 있으며, 바이너리 호환성을 확보할 수 있다. 반면, 메모리 사용량 측면에서 비효율적일 수 있다.

Who Owns the Memory? Part 3: How Big Is your Type?