Rust 的 Option<Vec<T>> 如何以及为何优化为 24 字节?

问题描述 投票:0回答:1

令我惊讶的是

Option<Vec<T>>
Vec<T>
的大小相同:

fn main() {
  println!(
    "u128: {} -> {}",
    size_of::<u128>(),
    size_of::<Option<u128>>()
  );
  println!(
    "vec: {} -> {}",
    size_of::<Vec<u16>>(),
    size_of::<Option<Vec<u16>>>()
  );
}

评估至

u128: 16 -> 32
vec: 24 -> 24

那么

  1. Rust 如何表示

    None
    Option<Vec>
    情况?看起来正常的
    Vec
    的 24 个字节来自 3 个 8 字节字段:一个指针、一个字节容量和一个长度。我的猜测是它使用了
    None
    的空指针,但我不确定。如果
    Vec
    持有 2 个指针,Rust 是否仍然能够保持相同的内存布局?

  2. Rust 为什么要这样做?对于

    Option<u128>
    ,我们显然可以选择使用
    N
    字节,与
    N > 16
    一样长,而 Rust 选择
    N = 32
    。这当然有很好的特性,例如我们可以仅通过位移位(无乘法)来访问
    i
    的第
    Vec<Option<u128>>
    个元素。但如果这是理想的情况,Rust 不应该也将
    Option<Vec<T>>
    设为 32 字节吗?

Rust 版本:rustc 1.83.0-nightly (1bc403daa 2024-10-11)

rust memory-layout
1个回答
0
投票

Option<Vec<_>>

您已经发现了由

Vec
支持的利基价值优化。更具体地说:

NonZero

文档特别指出,缺少 0 可实现内存布局优化。

因此,

Option::<Vec<_>>::None
可以表示指针所在位置的 0(这与 NULL
*const u8
指针的有效实例不同),以及长度和容量所在位置的任意值。

我不确定你所说的持有两个指针的

Vec
是什么意思。添加一个额外的指针到
Vec
将会使
Vec
Option<Vec<_>>
的大小增加指针的大小。

Option<u128>

首先,我们假设

u128
的对齐方式是
16

println!("{}", std::mem::align_of::<u128>()); // 16

考虑值

vec![Some(0u128), Some(0u128)]
。为了健全性,两个
u128
值必须对齐。按照您的逻辑,
Vec
中的第一项必须至少占用 17 个字节(
u128
为 16 个字节,
enum
判别式为 1)。下一个对齐的内存位置(对齐的倍数)将是从
Vec
开头算起的 32 个字节。由于
Vec
无法在项目之间添加填充,因此填充必须在
Option<u128>
内,使其为 32 字节。

© www.soinside.com 2019 - 2024. All rights reserved.