本页目录

Box, Rc, Arc

Box 是单一所有者的堆分配(最简单),Rc 是单线程引用计数(共享所有权),Arc 是多线程原子引用计数。Weak 打破引用循环,内存布局上 Rc/Arc 的值和引用计数在堆上紧邻分配——理解这三者就是理解 Rust 的"不用 GC 但有引用计数"。

Box: 单一所有者的堆分配

let b = Box::new(42);               // 在堆上分配一个 i32
// stack: [8-byte ptr] → heap: [4-byte value: 42]

Box<T> 是 Rust 中最简单的堆分配——单一所有者,无引用计数。当 b 离开作用域时,堆内存被释放。与 C++ 的 std::unique_ptr<T> 相似,但 Rust 版本不需要 move semantics 关键字——所有权在编译时保证。

何时用 Box

  1. 递归类型⁠: Rust 必须在编译期知道类型大小。enum List { Cons(i32, List), Nil } 递归导致无限大小。解决方案:Cons(i32, Box<List>)——Box 大小固定(指针,8B),递归通过堆间接解决
  2. Trait object: Box<dyn Display> 存储任意实现了 Display 的类型
  3. 大值移栈到堆⁠: 如果有一个 [u8; 1000000],用 Box::new([0u8; 1000000]) 只在栈上放 8 字节指针
  4. DST (dynamically sized type): Box<[T]>, Box<str>, Box<dyn Trait>

Rc: 单线程引用计数

use std::rc::Rc;
let a = Rc::new(vec![1, 2, 3]);     // strong_count = 1
let b = Rc::clone(&a);              // strong_count = 2, 不复制 Vec 数据!
let c = Rc::clone(&a);              // strong_count = 3

内部布局(在堆上,紧挨分配):

heap: [strong_count: usize(8B)] [weak_count: usize(8B)] [T: data]
Rc<T>: ptr → 指向 T 的地址 (实际指向 strong_count 前面)

Rc::clone 只增加 strong_count——数据没有被复制。当最后一个 Rc<T> 被 drop → strong_count = 0 → 数据被释放。Rc 不实现 Send——其引用计数操作不是原子的,跨线程使用会导致数据竞争。

Arc: 多线程引用计数

use std::sync::Arc;
let a = Arc::new(vec![1, 2, 3]);
let b = Arc::clone(&a);            // atomic increment → thread-safe
std::thread::spawn(move || {
    println!("{:?}", b);           // b can be moved into thread
});

与 Rc 内部结构相同,但 strong/weak count 操作用 atomic 指令。Arc::cloneRc::clone 慢约 10x(atomic increment vs non-atomic increment),但对于堆分配来说仍是极快的(~10ns vs ~1ns)。

Weak: 防止循环引用

use std::rc::{Rc, Weak};
let strong = Rc::new(42);
let weak: Weak<_> = Rc::downgrade(&strong);  // 不增加 strong_count

drop(strong);                        // strong_count = 0 → 数据释放
assert!(weak.upgrade().is_none());   // weak 检测到数据已释放 → None

经典用途:树结构中父节点存 Weak 引用指向子节点。如果存 Rc,就是循环引用——父引用子、子引用父,谁也释放不了。Weak 不阻止数据被释放,通过 upgrade() 方法临时获取数据的访问权(可能返回 None)。

参考

  • Rust Book: Chapter 15.1-15.4
  • Rustonomicon: Arc atomicity, reference counting

Keywords: Box, Rc, Arc, Weak, reference counting, heap allocation, recursive type, DST, Drop, atomic