On this page
Box, Rc, Arc
Box is single-owner heap allocation (simplest), Rc is single-threaded reference counting (shared ownership), Arc is multi-threaded atomic reference counting. Weak breaks reference cycles; in memory layout, the value and reference count of Rc/Arc are allocated adjacently on the heap—understanding these three is understanding Rust’s "no GC but with reference counting."
Box: Single-Owner Heap Allocation
let b = Boxnew; // Allocate an i32 on the heap
// stack: [8-byte ptr] → heap: [4-byte value: 42]
Box<T> is Rust's simplest heap allocation—single owner, no reference counting. When b goes out of scope, the heap memory is freed. Similar to C++'s std::unique_ptr<T>, but the Rust version doesn't require move semantics keywords—ownership is guaranteed at compile time.
When to Use Box
- Recursive Types: Rust must know the type size at compile time.
enum List { Cons(i32, List), Nil }recursion leads to infinite size. Solution:Cons(i32, Box<List>)—Box has a fixed size (pointer, 8B), recursion is resolved indirectly via the heap. - Trait Objects:
Box<dyn Display>stores any type that implements Display. - Moving Large Values from Stack to Heap: If you have
[u8; 1000000], usingBox::new([0u8; 1000000])places only an 8-byte pointer on the stack. - DST (Dynamically Sized Type):
Box<[T]>,Box<str>,Box<dyn Trait>.
Rc: Single-Threaded Reference Counting
use Rc;
let a = new; // strong_count = 1
let b = clone; // strong_count = 2, does not copy Vec data!
let c = clone; // strong_count = 3
Internal layout (allocated adjacently on the heap):
heap: [strong_count: usize(8B)] [weak_count: usize(8B)] [T: data]
Rc<T>: ptr → points to the address of T (actually points before strong_count)
Rc::clone only increments the strong_count—the data is not copied. When the last Rc<T> is dropped → strong_count = 0 → data is freed. Rc does not implement Send—its reference counting operations are not atomic, and using it across threads will cause data races.
Arc: Multi-Threaded Reference Counting
use Arc;
let a = new;
let b = clone; // atomic increment → thread-safe
spawn;
Same internal structure as Rc, but strong/weak count operations use atomic instructions. Arc::clone is about 10x slower than Rc::clone (atomic increment vs non-atomic increment), but it is still extremely fast for heap allocation (~10ns vs ~1ns).
Weak: Preventing Reference Cycles
use ;
let strong = new;
let weak: = downgrade; // Does not increase strong_count
drop; // strong_count = 0 → data freed
assert!; // Weak detects data has been freed → None
Classic use case: In tree structures, parent nodes store Weak references to child nodes. If they stored Rc, it would be a reference cycle—parent references child, child references parent, neither can be freed. Weak does not prevent data from being freed; it temporarily grants access to the data via the upgrade() method (which may return None).
References
- 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