在 Rust 中,内存分配主要通过栈(Stack)和堆(Heap)进行,结合所有权系统实现安全高效的内存管理。

一、Rust 内存管理的核心思想

“编译时检查 + 明确的所有权”
Rust 不需要垃圾回收(GC),也不依赖手动内存管理(如 C/C++)。它通过编译时的规则检查,确保内存安全且高效,最终生成类似手动管理的高效代码。


二、四大核心机制

1. 所有权(Ownership)

  • 核心规则
    • 每个值有且只有一个所有者(变量)。
    • 当所有者离开作用域(如函数结束),值会被自动释放。
    • 赋值或传参时,默认是“移动”(move),原所有者失效。
rust 复制代码
fn main() {
    let s1 = String::from("hello"); // s1 是所有者
    let s2 = s1; // s1 的值被移动到 s2,s1 失效!
    // println!("{}", s1); // 这里会报错!
}

2. 借用(Borrowing)

  • 引用(Reference):允许临时访问值,但不拥有它。
  • 规则
    • 同一时间,要么只能有一个可变引用(&mut),要么有多个不可变引用(&)。
    • 引用必须始终有效(不能悬空)。
rust 复制代码
fn main() {
    let mut s = String::from("hello");
    let r1 = &s;      // 不可变借用
    let r2 = &s;      // 另一个不可变借用(允许)
    // let r3 = &mut s; // 这里报错!不能同时存在可变和不可变借用

    println!("{}, {}", r1, r2);
}

3. 生命周期(Lifetime)

  • 作用:确保引用在有效范围内使用,避免悬垂指针。
  • 标注:编译器多数情况能自动推断,复杂时需要手动标注。
rust 复制代码
// 告诉编译器:返回的引用至少和输入的某个引用活的一样长
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

4. 智能指针(Smart Pointers)

  • 用途:管理堆内存,扩展所有权机制。
  • 常见类型
    • Box<T>:将值分配在堆上,用于明确数据大小或转移所有权。
    • Rc<T>:引用计数,允许同一数据多个只读所有者(仅单线程)。
    • Arc<T>:线程安全的引用计数(多线程用)。
    • RefCell<T>:运行时检查借用规则(允许“内部可变性”)。
rust 复制代码
use std::rc::Rc;

fn main() {
    let data = Rc::new(5);      // 引用计数 +1
    let data_clone = Rc::clone(&data); // 引用计数 +1(共享)
    println!("Count: {}", Rc::strong_count(&data)); // 输出 2
}

三、堆(Heap)与栈(Stack)

  • :自动分配/释放,存放固定大小的数据(如整数、结构体)。
  • :手动请求内存(通过 BoxString 等),存放动态大小数据。
  • Rust 的策略
    • 默认在栈上分配(高效)。
    • Box::new() 或智能指针将数据移到堆上。
    • 离开作用域时,堆内存自动释放(通过 Drop trait)。

栈内存分配::

  • 特点​:分配速度快、大小固定、自动释放。
  • ​适用场景​:存储基本类型(如 i32、f64)和固定大小的结构体。

堆内存分配:

  • 特点​:动态分配、生命周期灵活、需要手动管理(通过智能指针)。
  • 适用场景​:动态大小数据(如字符串、动态数组)或大对象。

四、内存安全保证

Rust 在编译时检查以下问题:

  1. 空指针:用 Option<T> 替代 null
  2. 野指针:通过生命周期和借用规则避免。
  3. 双重释放:所有权机制确保每个值只释放一次。
  4. 数据竞争:借用规则防止同时读写。
rust 复制代码
fn no_dangling() -> String {
    let s = String::from("hello");
    s // 返回 s,所有权转移出去,不会在函数结束时释放!
}

五、与其他语言对比

特性 C/C++ Java/Go Rust
内存管理 手动 垃圾回收(GC) 编译时所有权
性能 最高 有 GC 开销 接近 C/C++
安全性 易出错 较安全 编译时保证安全
学习曲线 中等 较低 较高