内存安全保证
问题
Rust 如何在没有垃圾回收的情况下保证内存安全?
答案
Rust 通过编译时检查而非运行时机制来保证内存安全,核心是三大支柱:
Rust 消除的内存错误类别
| 错误类型 | C/C++ | Rust | 机制 |
|---|---|---|---|
| 空指针解引用 | 常见 | 编译时阻止 | Option<T> 替代空指针 |
| 悬垂引用 | 常见 | 编译时阻止 | 生命周期检查 |
| 双重释放 | 常见 | 编译时阻止 | 所有权唯一 |
| 使用后释放 | 常见 | 编译时阻止 | Move 语义 |
| 缓冲区溢出 | 常见 | 运行时 panic | 边界检查 |
| 数据竞争 | 常见 | 编译时阻止 | Send/Sync + 借用规则 |
| 内存泄漏 | 常见 | 可能发生 | Rc 循环引用、mem::forget |
重要
Rust 不保证没有内存泄漏。Rc 循环引用、mem::forget、Box::leak 都可能导致泄漏。泄漏是安全的(不会导致 UB),只是浪费资源。
安全代码 vs unsafe 代码
// 安全代码:编译器保证所有规则
fn safe_example() {
let mut v = vec![1, 2, 3];
let r = &v[0];
// v.push(4); // ❌ 编译错误:r 还在借用 v
println!("{}", r);
v.push(4); // ✅ r 不再使用
}
// unsafe 代码:程序员承担安全责任
unsafe fn dangerous() -> i32 {
let ptr: *const i32 = &42;
*ptr // 解引用裸指针
}
关于 unsafe Rust 的详细内容请参考 unsafe Rust。
常见面试问题
Q1: Rust 能完全防止所有 Bug 吗?
答案:
不能。Rust 的安全保证有明确边界:
- 能防止:内存错误(悬垂引用、双重释放、数据竞争等)
- 不能防止:逻辑错误、死锁、内存泄漏、整数溢出(release 模式下 wrapping)
Q2: Rust 与 Go/Java 的安全模型有什么区别?
答案:
| 语言 | 内存管理 | 安全保证时机 | 代价 |
|---|---|---|---|
| Rust | 所有权 + RAII | 编译时 | 学习曲线、编译时间 |
| Go | GC | 运行时 | GC 停顿、内存开销 |
| Java | GC | 运行时 | GC 停顿、NullPointerException |
| C/C++ | 手动 | 无保证 | 安全完全靠程序员 |
Rust 独特之处在于:零运行时开销 + 编译时安全保证。