2.1 程序内存回顾

01-程序内存回顾 — Comprehensive Rust

译文 · 基于 Comprehensive Rust

原文链接: https://google.github.io/comprehensive-rust/memory-management/review.html

2.1 程序内存回顾

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

  • 栈(Stack):存放局部变量的连续内存区域。

    • 值的大小在编译期已知且固定。
    • 极快:只需移动栈指针。
    • 易于管理:随函数调用进出。
    • 内存局部性很好。
  • 堆(Heap):存放函数调用之外的值。

    • 值的大小在运行时动态确定。
    • 比栈稍慢:需要一些簿记开销。
    • 不保证内存局部性。

示例

创建 String 会把固定大小的元数据放在栈上,把动态大小的数据(实际字符串内容)放在堆上:

1
2
3
4
5
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
fn main() {
    let s1 = String::from("Hello");
}
 Stack
.- - - - - - - - - - - - - -.      Heap
:                           :     .- - - - - - - - - - - - - - - -.
:    s1                     :     :                               :
:   +-----------+-------+   :     :                               :
:   | capacity  |     5 |   :     :   +----+----+----+----+----+  :
:   | ptr       |     o-+---+-----+-->| H  | e  | l  | l  | o  |  :
:   | len       |     5 |   :     :   +----+----+----+----+----+  :
:   +-----------+-------+   :     :                               :
:                           :     :                               :
`- - - - - - - - - - - - - -'     `- - - - - - - - - - - - - - - -'
  • 可以提到:String 底层由 Vec 支撑,因此有 capacity 与 length;若可变,可通过在堆上重新分配来增长。

  • 若学员问起,可说明底层内存由 System Allocator 在堆上分配,也可通过 Allocator API 实现自定义分配器。

延伸阅读

可以用 unsafe Rust 查看内存布局。但务必强调:这样做本身就是不安全的!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
fn main() {
    let mut s1 = String::from("Hello");
    s1.push(' ');
    s1.push_str("world");
    // 切勿在生产代码中这样做!仅用于教学演示。
    // String 不保证其布局,这样做可能导致未定义行为。
    unsafe {
        let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1);
        println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}");
    }
}
最后修改 August 11, 2026: 更新 (70a5af133)