Rust内存布局

题图忘了来自哪里..

整型,浮点型,struct,vec!,enum

本文是对 Rust内存布局 的学习与记录

复制代码
struct A {
    a: i64,
    b: u64,
}

struct B {
    a: i32,
    b: u64,
}

struct C {
    a: i64,
    b: u64,
    c: i32,
}

struct D {
    a: i32,
    b: u64,
    c: i32,
    d: u64,
}

fn main() {
    println!("i32类型占的内存空间为:{}字节", std::mem::size_of::<i32>());
    println!("i64类型占的内存空间为:{}字节", std::mem::size_of::<i64>());
    println!(
        "[i64;4]占的内存空间为:{}字节",
        std::mem::size_of::<[i64; 4]>()
    );

    println!("结构体A占的内存空间为:{}字节", std::mem::size_of::<A>());
    println!("结构体B占的内存空间为:{}字节", std::mem::size_of::<B>());
    println!("结构体C占的内存空间为:{}字节", std::mem::size_of::<C>());
    println!("结构体D占的内存空间为:{}字节", std::mem::size_of::<D>());
}

输出

复制代码
i32类型占的内存空间为:4字节
i64类型占的内存空间为:8字节
[i64;4]占的内存空间为:32字节
结构体A占的内存空间为:16字节
结构体B占的内存空间为:16字节
结构体C占的内存空间为:24字节
结构体D占的内存空间为:24字节

没啥好说的,和Go一样,struct会存在内存对齐/内存填充(8字节对齐)

D是因为编译器会优化内存布局,字段顺序重排

Rust中的Vec!和Go中的slice差不多,都是占24Byte,三个字段

复制代码
struct SimpleVec<T> {
    len: usize,      // 8
    capacity: usize, //8
    data: *mut T,    //8
}

fn main() {
    println!(
        "Vec!类型占的内存空间为:{}字节",
        std::mem::size_of::<SimpleVec<i32>>()
    );

    println!(
        "Option<i64>类型占的内存空间为:{}字节",
        std::mem::size_of::<Option<i64>>()
    );
}

Vec!类型占的内存空间为:24字节
Option<i64>类型占的内存空间为:16字节

但是对于enum类型,

会有一个tag字段,uint64,来标记变体,是None值还是Some值

复制代码
struct Option {
    uint64 tag; // 占8字节 Some None
    i64; //实际存放的数据
}

struct SimpleVec<T> {
    len: usize,      // 8
    capacity: usize, //8
    data: *mut T,    //8
}

enum Data {
    // tag,uint64,8字节
    I32(i32),             //  4字节,但需内存对齐到8字节?
    F64(f64),             // 8字节
    Bytes(SimpleVec<u8>), // 24字节
}

fn main() {
    println!(
        "Data这个Enum类型占的内存空间为:{}字节",
        std::mem::size_of::<Data>()
    );
}

输出为:

Data这个Enum类型占的内存空间为:32字节

Rust的enum类似C++ std::variant的实现(大致是用union实现的)

union的内存大小是其成员中最大的那个成员的大小,

类似的,对于Data这个Enum类型,会选择最大的那个成员的大小

所以24+tag的8字节,最终为32字节 (tag在这里就用来标识其为i32,还是f64,或者是Vec )

嵌套的枚举:

复制代码
struct SimpleVec<T> {
    len: usize,      // 8
    capacity: usize, //8
    data: *mut T,    //8
}

enum Data {
    // tag,uint64,8字节
    I32(i32),             //  4字节,但需内存对齐到8字节?
    F64(f64),             // 8字节
    Bytes(SimpleVec<u8>), // 24字节
}

type OptData = Option<Data>;

fn main() {
    println!(
        "OptData这个Option类型占的内存空间为:{}字节",
        std::mem::size_of::<OptData>()
    );
}

输出:

OptData这个Option类型占的内存空间为:32字节

因为编译器会对嵌套的枚举类型进行优化,会将其tag展开, 把多个tag合在一起了,类似下面:

展开变成一个枚举(None是uint64,能标识非常多信息)

复制代码
type OptData = Option<Data>;

enum Option {
    Some,
    None,
}

enum OptData_ {
    I32(i32);
    F64(f64);
    Bytes(SimpleVec<u8>),
    None
}

元组tuple

rust中的元组大小固定吗?

在Rust中,元组的大小是固定的。这里解释一下元组大小固定的含义:

  • 元组中的元素类型和数量在编译期就已经确定,不能在运行期修改。
  • 编译器会根据元组中元素的类型,预先分配足够的内存用于存储这些元素。
  • 元组的内存布局和大小也在编译期就确定下来了,运行期不会改变。
  • 尝试创建包含不同类型或数量元素的元组,是编译时错误。

举个例子:

复制代码
let tuple = (1, 2.0, "three");

这里元组包含一个i32,一个f64和一个字符串。编译器会预先知道:

  • 元组元素类型为i32, f64, &str
  • i32占用4字节,f64占用8字节,&str占据一个指针的空间
  • 所以该元组占用的内存大小为4 + 8 + 8 = 20字节

这20字节的内存在编译时就已分配,运行期不会改变。

如果后续试图给这个元组添加或减少元素,编译都会报错。

所以说,元组的大小和内容是固定的,这是Rust实现方式的一部分。

更多可参考 Rust 数据内存布局

本文由mdnice多平台发布

相关推荐
superman超哥12 分钟前
Rust 异步性能的黑盒与透视:Tokio 监控与调优实战
开发语言·后端·rust·编程语言·rust异步性能·rust黑盒与透视·tokio监控与调优
Mr -老鬼24 分钟前
Rust 知识图谱 -进阶部分
开发语言·后端·rust
guchen6639 分钟前
CircularBuffer 优化历程:从数组越界到线程安全的完美实现
后端
古城小栈40 分钟前
Cargo.toml
开发语言·后端·rust
悟空码字1 小时前
10分钟搞定!SpringBoot集成腾讯云短信全攻略,从配置到发送一气呵成
java·spring boot·后端
星浩AI1 小时前
从0到1:用LlamaIndex工作流构建Text-to-SQL应用完整指南
人工智能·后端·python
用户298698530141 小时前
C# Word文档页面操作:告别手动,高效掌控你的Word文档!
后端·c#·.net
未来龙皇小蓝1 小时前
Spring注入Bean流程及其理解
java·spring boot·后端·spring·代理模式
用户2190326527351 小时前
SpringCloud分布式追踪深度实战:Sleuth+Zipkin从入门到生产部署全攻略
分布式·后端·spring cloud
陈随易1 小时前
Bun v1.3.6发布,内置tar解压缩,各方面提速又提速
前端·后端