메모리 내 데이터 배치 최적화는 Rust의 핵심 특징으로, 코드의 안전성을 잃지 않고 리소스를 절약할 수 있게 해 줍니다. Enum Layout은 컴파일러가 enum의 변형(구조체 또는 원시 타입의 변형)을 어떻게 배치하는지를 의미하며, 모든 구조체의 필드도 포함됩니다. 다른 언어에서는 이러한 최적화가 종종 숨겨져 있지만, Rust에서는 필드 순서를 고려하여 메모리 낭비를 피하는 것이 매우 중요합니다.
구조체에서 필드 순서를 잘못 선택하면 데이터 정렬의 특성으로 인해 구조체의 크기가 "불어날" 수 있습니다. 연관된 데이터를 가진 enum의 경우 상황이 복잡해집니다. enum의 크기는 가장 큰 변형의 크기와 구분자의 크기로 결정됩니다. 이를 무시하면 메모리 과다 사용과 캐시 성능 저하로 이어집니다.
구조체와 enum의 효과적인 패킹을 위해서는 "넓은" 필드를 먼저 배치하고, 더 좁은 필드를 그 뒤에 배치하며, 컴파일러가 추가할 수 있는 패딩을 고려해야 합니다. enum의 경우, 변형 구조를 선택할 때 최대 크기로 가지 않도록 해야 합니다.
코드 예시:
struct BadAlign { a: u8, b: u32, c: u16, } struct GoodAlign { b: u32, c: u16, a: u8, } enum Packet { A(u8), B(u32, [u8; 10]), }
주요 특징:
필드 순서를 바꾸어서 구조체 크기를 줄일 수 있나요?
네. 필드를 크기 순으로 배치하면 컴파일러가 패딩의 양을 줄이고, 따라서 구조체의 전체 크기를 줄이는 경우가 많습니다.
println!("{}", std::mem::size_of::<BadAlign>()); // 예를 들어, 12 println!("{}", std::mem::size_of::<GoodAlign>()); // 예를 들어, 8
필드의 어떤 순서가 필드 접근 성능에 영향을 미치나요?
순서 자체는 필드 접근 속도에 영향을 미치지 않습니다. 그러나 낮은 수준에서 구조체를 순차적으로 순회할 때(SIMD 명령어로 작업하거나, 구조체 배열을 루프에서 처리할 때), 올바른 정렬은 캐시 활용을 개선하여 접근 속도를 높일 수 있습니다.
enum의 한 변형이 매우 크다면, 다른 변형이 있더라도 모든 enum 인스턴스가 동일한 메모리를 차지하나요?
네, enum의 크기는 항상 변형 중 최대 크기와 구분자의 크기로 결정됩니다. 어떤 Packet도 A에 들어있더라도 B의 크기를 차지합니다.
** 부정적인 사례
구조체의 필드가 u8 다음에 u64입니다. 100000개의 레코드 배열에서 사용하면 패딩 때문에 최대 1GB의 메모리를 소모할 수 있습니다.
장점:
단점:
** 긍정적인 사례
구조체를 필드의 너비 순으로 정렬하고, 큰 변형은 Box에 보관하고 작은 것은 제자리에 둡니다.
장점:
단점: