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)分配的类型(例如String或Vec<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.0和10.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>将结构体分配到堆上:
- 结构体较大:堆分配可以避免栈溢出。
- 需要动态生命周期:例如在递归数据结构中,堆分配是必要的。