0%

Rust 的内存布局设计强调效率、安全性和明确性,其布局规则由类型定义和编译器优化共同决定。以下是对 Rust 各类对象内存布局的详细分析:


一、基础类型布局

  1. 标量类型

    • 整数i32/u32 占 4 字节,对齐 4 字节
    • 浮点数f64 占 8 字节,对齐 8 字节
    • 布尔值bool 占 1 字节(0x000x01
    • 字符char 占 4 字节(UTF-8 编码)
  2. 复合类型

    • **元组 (T1, T2)**:字段顺序排列,按最大对齐要求填充。
      1
      (i32, u8) // 布局:[i32][u8][填充3字节] → 总大小8字节
    • **数组 [T; N]**:连续存储,无填充。
      1
      [u16; 3] // 布局:[u16][u16][u16] → 总大小6字节

二、结构体(Struct)布局

1. 默认布局(Rust布局)

  • 字段顺序:编译器可能重排字段以最小化填充。
  • 对齐:按字段中最大对齐要求对齐。
  • 示例
    1
    2
    3
    4
    5
    6
    struct RustStruct {
    a: u8, // 1字节
    b: u32, // 4字节(对齐4)
    c: u16, // 2字节
    }
    // 优化后布局:[b(4)][c(2)][a(1)][填充1] → 总大小8字节

2. #[repr(C)] 布局

  • 字段顺序:严格按声明顺序排列。
  • 对齐:同 C 语言规则。
  • 示例
    1
    2
    3
    4
    5
    6
    7
    #[repr(C)]
    struct CStruct {
    a: u8, // 1字节
    b: u32, // 4字节(对齐4)
    c: u16, // 2字节
    }
    // 布局:[a(1)][填充3][b(4)][c(2)] → 总大小12字节

3. 特殊布局属性

  • **#[repr(packed)]**:取消填充(可能牺牲性能)。
  • **#[repr(align(n))]**:强制对齐到 n 字节。

三、枚举(Enum)布局

1. 带数据枚举

  • 标签联合(Tagged Union)
    • 标签(Discriminant):标识当前变体(通常为 usize)。
    • 联合体(Union):存储变体数据。
  • 示例
    1
    2
    3
    4
    5
    6
    enum MyEnum {
    A, // 无数据
    B(u32), // 包含u32
    C { x: u8, y: u8 } // 包含结构
    }
    // 布局:[标签][联合体] → 标签大小 + 最大变体大小

2. 优化策略

  • 空指针优化Option<&T>None0 表示,无需额外标签。
  • 标签压缩:尝试用最小整数存储标签。
  • 变体数据内联:小数据类型直接内联。

3. #[repr(u8)]

  • 显式指定标签类型:
    1
    2
    3
    4
    5
    #[repr(u8)]
    enum HttpStatus {
    Ok = 200,
    NotFound = 404,
    }

四、动态类型与智能指针

  1. **切片(Slice) &[T]**:

    • 胖指针[指针, 长度] → 16 字节(64位系统)。
    • 内存连续:元素紧密排列。
  2. **字符串 &str**:

    • 同切片布局:[指针, 长度]
  3. **Box<T>**:

    • 瘦指针:指向堆内存 → 8 字节(64位系统)。
    • 内存布局:堆上存储 T 的值。
  4. **Vec<T>**:

    • 三元组[指针, 长度, 容量] → 24 字节(64位系统)。
    • 堆内存:连续存储元素。
  5. **特征对象 &dyn Trait**:

    • 胖指针[数据指针, vtable指针] → 16 字节。
    • vTable:包含方法指针、类型大小和对齐信息。

五、零大小类型(ZST)

  • 特点:大小=0,对齐=1。
  • 示例struct Nothing;()
  • 优化:编译器消除ZST的实际内存分配。

六、动态大小类型(DST)

  • 特点:编译期大小未知(如 [T]dyn Trait)。
  • 使用限制:必须通过指针(如 &[T]Box<dyn Trait>)间接访问。

七、内存对齐控制

  • 对齐规则
    1
    2
    3
    4
    struct AlignExample {
    a: u8, // 对齐1
    b: u32, // 对齐4 → 结构体对齐=4
    }
  • 手动对齐
    1
    2
    #[repr(align(8))]
    struct ForceAligned(u32); // 强制对齐到8字节

八、查看内存布局的工具

  1. std::mem 函数
    1
    2
    std::mem::size_of::<T>()   // 类型大小
    std::mem::align_of::<T>() // 对齐要求
  2. **#[derive(Debug)]**:结合调试器查看内存。
  3. 第三方库:如 std::mem::transmute(谨慎使用)、bytemuck

总结表

类型 布局特点 示例大小(64位)
标量类型 紧密排列,无填充 i32: 4字节
默认结构体 字段重排优化填充 优化后可能≤12字节
#[repr(C)] 结构体 严格声明顺序,可能填充 可能12字节
枚举 标签联合 + 优化策略 通常8-24字节
切片 &[T] 胖指针(数据指针 + 长度) 16字节
Box<T> 瘦指针(指向堆数据) 8字节
Vec<T> 三元组(指针 + 长度 + 容量) 24字节
特征对象 &dyn T 胖指针(数据指针 + vTable指针) 16字节
ZST 不占实际空间 0字节

通过理解这些规则,您可以预测数据的内存占用、优化性能,并安全地进行FFI交互。Rust的布局设计在保证安全的同时,尽可能追求高效率。