回顾:程序的内存分配

程序通过以下两种方式分配内存:

  • 栈:局部变量的连续内存区域。

  • 值在编译时具有已知的固定大小。

  • 速度极快:只需移动一个栈指针。
  • 易于管理:遵循函数调用规则。
  • 优秀的内存局部性。
  • 堆:函数调用之外的值的存储。

  • 值具有动态大小,具体大小需在运行时确定。

  • 比栈稍慢:需要向系统申请空间。
  • 不保证内存局部性。

示例

Creating a String puts fixed-sized metadata on the stack and dynamically sized data, the actual string, on the heap:

1. fn main() {
2. let s1 = String::from("Hello");
3. }

19.1. 回顾:程序的内存分配 - 图1

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!

1. fn main() {
2. let mut s1 = String::from("Hello");
3. s1.push(' ');
4. s1.push_str("world");
5. // DON'T DO THIS AT HOME! For educational purposes only.
6. // String provides no guarantees about its layout, so this could lead to
7. // undefined behavior.
8. unsafe {
9. let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1);
10. println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}");
11. }
12. }