Box
一、堆与栈的对比
-
栈内存 • 连续分配,从高位地址向下增长,大小有限(主线程 8MB,普通线程 2MB) • 高效分配/释放:函数调用时自动管理临时栈,所有权转移时栈数据浅拷贝 • 适合小型数据(寄存器/缓存友好)
-
堆内存 • 非连续分配,从低位地址向上增长,大小受物理内存限制 • 所有权明确:堆数据通过栈上的智能指针(如
Box<T>
)管理 • 适合大型数据:避免深拷贝,所有权转移仅复制指针
二、Box<T>
的核心作用
将数据存储在堆上,栈中保留智能指针。零额外性能开销,仅需堆分配成本。
三、使用场景
-
显式堆分配
let a = Box::new(3); // 堆上存储 3,a 为栈上的智能指针 println!("{}", *a); // 显式解引用
-
避免大数据的深拷贝
let arr = Box::new([0; 1000]); let arr1 = arr; // 仅复制指针,堆数据未拷贝
-
解决动态大小类型(DST)问题 • 递归类型:通过
Box
固定大小enum List { Cons(i32, Box<List>), // 递归成员用 Box 包装 Nil, }
-
特征对象(Trait Object)
let elems: Vec<Box<dyn Draw>> = vec![Box::new(Button), Box::new(Select)]; // 存储不同类型,统一为 `dyn Draw` 特征对象
四、内存布局
-
普通
Vec<i32>
• 栈指针 → 堆上的连续数组 -
Vec<Box<i32>>
• 栈指针 → 堆上的Box
指针数组 → 每个Box
指向堆上的实际值let sum = **arr[0] + **arr[1]; // 双重解引用获取值
五、Box::leak
方法
• 作用:消费 Box
并泄漏内存,强制值拥有 'static
生命周期
• 场景:运行时初始化但需全局有效的数据(如配置)
let s = Box::leak(String::new().into_boxed_str());
// s: &'static str
六、注意事项
- 显式解引用:表达式不会隐式解引用,需用
*
或**
- 自动释放:
Box
离开作用域时自动调用Drop
释放堆内存 - 性能权衡:堆分配适合大型数据,小型数据优先用栈
总结
Box<T>
是 Rust 中最基础的智能指针,用于堆分配、解决所有权转移效率问题、处理递归类型和特征对象。理解其内存布局及适用场景,能有效平衡性能与代码复杂度。