You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
|
|
# `Box<T>`堆对象分配
|
|
|
|
|
关于作者帅不帅,估计争议还挺多的,但是如果说`Box<T>`是不是Rust中最常见的智能指针,那估计没有任何争议。因为`Box<T>`允许你将一个值分配到堆上,然后在栈上保留一个智能指针指向堆上的数据。
|
|
|
|
|
|
|
|
|
|
之前我们在[所有权章节](https://course.rs/basic/ownership/ownership.html#栈stack与堆heap)简单讲过堆栈的概念,这里再补充一些。
|
|
|
|
|
|
|
|
|
|
## Rust中的堆栈
|
|
|
|
|
高级语言Python/Java等往往会弱化堆栈的概念,但是要用好C/C++/Rust,就必须对堆栈有深入的了解,原因是两者的内存管理方式不同: 前者有GC垃圾回收机制, 因此无需你去关心内存的细节。
|
|
|
|
|
|
|
|
|
|
栈内存从高位地址向下增长,且栈内存是连续分配的,一般来说**操作系统对栈内存的大小都有限制**,因此C语言中无法创建任意长度的数组。在Rust中, `main`线程的[栈大小是`8MB`](https://zhuanlan.zhihu.com/p/446039229),普通线程是`2MB`,然后在函数调用时会在其中创建一个临时栈空间,调用结束后Rust会让这个栈空间里的对象自动进入`Drop`流程,最后栈顶指针自动移动到上一个调用栈顶,无需程序员手动干预,因而栈内存申请和释放是非常高效的。
|
|
|
|
|
|
|
|
|
|
与栈相反,堆上内存则是从低位地址向上增长,**堆内存通常只受物理内存限制**,而且通常是不连续的, 因此从性能的角度看,栈往往比对堆更高。
|
|
|
|
|
|
|
|
|
|
相比其它语言,Rust堆上对象还有一个特殊之处,它们都拥有一个所有者,因此受所有权规则的限制:当赋值时,发生的是所有权的转移(只需浅拷贝栈上的引用或智能指针即可), 例如以下代码:
|
|
|
|
|
```rust
|
|
|
|
|
fn main() {
|
|
|
|
|
let b = foo("world");
|
|
|
|
|
println!("{}", b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn foo(x: &str) -> String {
|
|
|
|
|
let a = "Hello, ".to_string() + x;
|
|
|
|
|
a
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
在`foo`函数中,`a`是`String`类型,它其实是一个智能指针结构体,该智能指针存储在函数栈中,指向堆上的字符串数据。当被从`foo`函数转移给`main`中的`b`变量时,栈上的智能指针被复制一份赋予给`b`,而底层数据无需发生改变,这样就完成了所有权从`foo`函数内部到`b`的转移.
|
|
|
|
|
|
|
|
|
|
#### 堆栈的性能
|
|
|
|
|
很多人可能会觉得栈的性能肯定比堆高,其实未必。 由于我们在后面的性能专题会专门讲解堆栈的性能问题,因此这里就大概给出结论:
|
|
|
|
|
|
|
|
|
|
- 小型数据,在栈上的分配性能和读取性能都要比堆上高
|
|
|
|
|
- 中型数据,栈上分配性能高,但是读取性能和堆上并无区别,因为无法利用寄存器或CPU高速缓存,最终还是要经过一次内存寻址
|
|
|
|
|
- 大型数据,只建议在堆上分配和使用
|
|
|
|
|
|
|
|
|
|
总之栈的分配速度肯定比堆上快,但是读取速度往往取决于你的数据能不能放入寄存器或CPU高速缓存。 因此不要仅仅因为堆上性能不如栈这个印象,就总是优先选择栈,导致代码更复杂的实现。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Box::leak
|