本页目录
Box, Rc, Arc
Box 是单一所有者的堆分配(最简单),Rc 是单线程引用计数(共享所有权),Arc 是多线程原子引用计数。Weak 打破引用循环,内存布局上 Rc/Arc 的值和引用计数在堆上紧邻分配——理解这三者就是理解 Rust 的"不用 GC 但有引用计数"。
Box: 单一所有者的堆分配
let b = Boxnew; // 在堆上分配一个 i32
// stack: [8-byte ptr] → heap: [4-byte value: 42]
Box<T> 是 Rust 中最简单的堆分配——单一所有者,无引用计数。当 b 离开作用域时,堆内存被释放。与 C++ 的 std::unique_ptr<T> 相似,但 Rust 版本不需要 move semantics 关键字——所有权在编译时保证。
何时用 Box
- 递归类型: Rust 必须在编译期知道类型大小。
enum List { Cons(i32, List), Nil }递归导致无限大小。解决方案:Cons(i32, Box<List>)——Box 大小固定(指针,8B),递归通过堆间接解决 - Trait object:
Box<dyn Display>存储任意实现了 Display 的类型 - 大值移栈到堆: 如果有一个
[u8; 1000000],用Box::new([0u8; 1000000])只在栈上放 8 字节指针 - DST (dynamically sized type):
Box<[T]>,Box<str>,Box<dyn Trait>
Rc: 单线程引用计数
use Rc;
let a = new; // strong_count = 1
let b = clone; // strong_count = 2, 不复制 Vec 数据!
let c = clone; // 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 Arc;
let a = new;
let b = clone; // atomic increment → thread-safe
spawn;
与 Rc 内部结构相同,但 strong/weak count 操作用 atomic 指令。Arc::clone 比 Rc::clone 慢约 10x(atomic increment vs non-atomic increment),但对于堆分配来说仍是极快的(~10ns vs ~1ns)。
Weak: 防止循环引用
use ;
let strong = new;
let weak: = downgrade; // 不增加 strong_count
drop; // strong_count = 0 → 数据释放
assert!; // 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