Optimizing data layout in memory is a key feature of Rust, allowing resource savings without sacrificing code safety. Enum Layout refers to how the compiler arranges the variants of enums (with struct or primitive variants) as well as the fields of any structure. In other languages, such optimization is often hidden, but in Rust, the order of fields must be considered to avoid memory overuse.
If the order of fields in a structure is poorly chosen, due to the specifics of data alignment, the structure will start to "inflate" in size. For enums with associated data, the situation becomes more complicated — the size of the enum is determined by the largest variant plus the size of the discriminator. Overlooking this leads to excessive memory consumption and reduced CPU cache performance.
To efficiently pack structures and enums, it is recommended to place the most "wide" fields first, followed by the narrower ones, and to consider the paddings that the compiler may add. For enums, choose the structure of the variants so that they do not aim for the maximum size unless justified.
Example code:
struct BadAlign { a: u8, b: u32, c: u16, } struct GoodAlign { b: u32, c: u16, a: u8, } enum Packet { A(u8), B(u32, [u8; 10]), }
Key features:
Can changing the order of fields make a structure smaller?
Yes. If fields are arranged in decreasing order of size, the compiler often reduces the amount of padding, thereby decreasing the overall size of the structure.
println!("{}", std::mem::size_of::<BadAlign>()); // e.g., 12 println!("{}", std::mem::size_of::<GoodAlign>()); // e.g., 8
Does any order of fields affect performance when accessing them?
The order itself does not affect the speed of access through the fields. However, during sequential traversal of the structure at a low level (for example, with SIMD instructions or when working with arrays of structures in a loop), correct alignment speeds up access due to better cache utilization.
If one variant of an enum is very large, will every instance of the enum occupy the same amount of memory, even if it holds other variants?
Yes, the size of the enum is always determined by the largest variant plus the discriminator. Any Packet will occupy the size of B, even if it contains A.
**Negative Case
In a structure, u8 fields are followed by u64. Using it in an array of 100,000 records consumes up to a gigabyte of memory due to paddings.
Pros:
Cons:
**Positive Case
Structures sorted by field width, with large variants of the enum moved to a Box, while smaller ones remain in-place.
Pros:
Cons: