内存知识网 手机版
首页 > 内存知识 >

Rust 结构体的内存布局

时间:

本文将介绍在Rust中处理结构体(struct)时的内存分配方式。如果你尚未了解结构体的基本概念,建议先阅读相关入门文章。如果你对Rust中的内存管理还不熟悉,本文将是一个不错的入门指南。

固定大小字段的结构体

当结构体的所有字段在编译时大小已知(例如整数、浮点数或其他固定大小字段的结构体)时,该结构体本身具有固定大小,并完全存储在栈(stack)上。

struct Point {
    x: f64,
    y: f64,
} // 结构体尚未分配内存

fn main() {
    let p = Point { x: 3.0, y: 4.0 }; // 结构体分配在栈上
    println!("Point: ({}, {})", p.x, p.y);
}

内存分配

  • 结构体本身(两个f64值的内存)直接分配在栈上,并与变量p关联。
  • 每个字段在内存中是连续存储的。
  • 结构体定义中字段的顺序决定了它们的内存布局。

包含引用或动态大小字段的结构体

如果结构体包含引用或涉及堆(heap)分配的类型(例如StringVec<T>),则固定大小的字段仍存储在栈上,而堆分配的数据则以指针的形式存储。

struct Person {
    name: String,
    age: u32,
}

fn main() {
    let person = Person {
        name: String::from("Alice"), // 字符串在堆上分配
        age: 30, // 存储在栈上
    };
    println!("{} is {} years old.", person.name, person.age);
}

内存分配

  • age字段直接存储在栈上。
  • name字段包含一个指向堆中字符串数据的指针。

在上述例子中,内存布局如下:

  • :包含结构体本身(包括name字段的指针)。
  • :存储字符串的实际内容(例如"Alice")。

元组结构体

元组结构体是普通结构体的一种变体,但没有命名字段。它们的内存分配方式与普通结构体相同。

struct Coordinates(f64, f64);

fn main() {
    let coords = Coordinates(5.0, 10.0);
    println!("Coordinates: ({}, {})", coords.0, coords.1);
}

在这里,字段5.010.0像固定大小的结构体一样,连续存储在内存中。

结构体的堆分配

结构体本身通常存储在栈上,除非使用智能指针(如Box<T>)显式地将其分配到堆上。

struct Point {
    x: f64,
    y: f64,
}

fn main() {
    let stack_point = Point { x: 1.0, y: 2.0 }; // 存储在栈上
    let heap_point = Box::new(Point { x: 3.0, y: 4.0 }); // 存储在堆上
    println!("Heap Point: ({}, {})", heap_point.x, heap_point.y);
}

使用规则

在以下情况下,可以考虑使用Box<T>将结构体分配到堆上:

  1. 结构体较大:堆分配可以避免栈溢出。
  2. 需要动态生命周期:例如在递归数据结构中,堆分配是必要的。