Rust 中“Option”的内存开销不是恒定的

Sar*_*lle 1 memory rust option-type

使用以下代码片段

use std::mem;

fn main() {
   println!("size Option(bool): {} ({})", mem::size_of::<Option<bool>>(), mem::size_of::<bool>());
   println!("size Option(u8): {} ({})", mem::size_of::<Option<u8>>(), mem::size_of::<u8>());
   println!("size Option(u16): {} ({})", mem::size_of::<Option<u16>>(), mem::size_of::<u16>());
   println!("size Option(u32): {} ({})", mem::size_of::<Option<u32>>(), mem::size_of::<u32>());
   println!("size Option(u64): {} ({})", mem::size_of::<Option<u64>>(), mem::size_of::<u64>());
   println!("size Option(u128): {} ({})", mem::size_of::<Option<u128>>(), mem::size_of::<u128>())
}
Run Code Online (Sandbox Code Playgroud)

我在 64 位机器上看到:

size Option(bool): 1 (1)
size Option(u8): 2 (1)
size Option(u16): 4 (2)
size Option(u32): 8 (4)
size Option(u64): 16 (8)
size Option(u128): 24 (16)
Run Code Online (Sandbox Code Playgroud)

因此开销不是恒定的并且会上升到8字节。我想知道为什么存储标签的开销不只是一个字节?我还想知道编译器选择什么表示形式?

Frx*_*rem 5

关于类型布局的 Rust 参考在这里发挥作用:

[...] 值的大小始终是其对齐方式的倍数。[...]

[默认]表示所保证的唯一数据布局是健全性所需的数据布局。他们是: [...]

  1. 类型的对齐方式至少是其字段的最大对齐方式。

因此 的大小Option<T>必须向上舍入到最接近的对齐方式T,即使只使用一个字节(甚至一位)来存储“值存在”的信息。

例外的是允许“空指针优化”的类型,其中Option<T>具有相同的大小,因为它可以使用 的无效状态之一来T表示。例如,只有两个状态,因此编译器将优化并使用剩余的 254 个 1 字节状态之一来表示for 。这适用于、、、、和。NoneTboolNoneOption<bool>bool&U&mut UfnBox<U>NonZero*NonNull<U>