回顾:程序的内存分配
程序通过以下两种方式分配内存:
-
栈:局部变量的连续内存区域。
- 值在编译时具有已知的固定大小。
- 速度极快:只需移动一个栈指针。
- 易于管理:遵循函数调用规则。
- 优秀的内存局部性。
-
堆:函数调用之外的值的存储。
- 值具有动态大小,具体大小需在运行时确定。
- 比栈稍慢:需要向系统申请空间。
- 不保证内存局部性。
示例
Creating a String
puts fixed-sized metadata on the stack and dynamically sized data, the actual string, on the heap:
fn main() { let s1 = String::from("Hello"); }
This slide should take about 5 minutes.
-
指出
String
底层由Vec
实现,因此它具有容量和长度,如果值可变,则可以通过在堆上重新分配存储空间进行增长。 -
如果学员提出相关问题,你可以提及我们不仅能使用[系统分配器]在堆上分配底层内存,还能使用 Allocator API 实现自定义分配器
探索更多
We can inspect the memory layout with unsafe
Rust. However, you should point out that this is rightfully unsafe!
fn main() { let mut s1 = String::from("Hello"); s1.push(' '); s1.push_str("world"); // DON'T DO THIS AT HOME! For educational purposes only. // String provides no guarantees about its layout, so this could lead to // undefined behavior. unsafe { let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1); println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}"); } }