202. Arc::clone Is a Refcount Bump, Not a Deep Copy — Share Big Data, Don't Duplicate It
big.clone() on a 50MB lookup table allocates 50MB every time a worker needs a copy. Wrap it in an Arc once and Arc::clone is just an atomic +1 on a counter — every owner reads the same bytes.
This closes out performance week, the afternoon pair to the morning’s entry() bite: that one was about not building a default you’ll throw away, this one is about not copying a payload you only ever read.
The trap: .clone() deep-copies the payload
When several owners each need “their own” handle to a large immutable value, the obvious move is to clone it. But Clone on a Vec/String/HashMap walks the data and allocates a fresh copy:
| |
Nobody mutates the data — they just read it — yet you paid for four independent copies. That’s pure waste.
The fix: one allocation, shared by reference count
Put the value behind an Arc<T> once. Now Arc::clone doesn’t touch the payload at all — it bumps an atomic reference count and hands back another pointer to the same allocation:
| |
The Arc::clone(&x) spelling (rather than x.clone()) is a convention worth keeping: at the call site it reads as “bump the counter,” so a reviewer knows a cheap pointer copy happened, not a 32MB memcpy.
This is what makes it cheap to send to threads
The same property is why Arc is the building block for sharing immutable data across threads — each thread gets a counted handle, all reading one copy:
| |
Four threads, one underlying Vec. Cloning the payload into each thread would have been four allocations; Arc::clone is four counter bumps.
When not to reach for it
Arc shines for data that’s large, shared, and read-only after construction. It’s not free: every clone and drop is an atomic operation, and the payload lives until the last handle goes away. For small Copy types (bite-200) a plain copy is cheaper than the atomic traffic. And if you need to mutate shared state, you want Arc<Mutex<T>> or Arc<RwLock<T>> (bite-160) — or Arc::make_mut (bite-113) for copy-on-write.
The bottom line
If you’re cloning a big value just to hand read-only access to several owners or threads, you’re copying bytes nobody changes. Wrap it in Arc once: every Arc::clone after that is an atomic increment over a shared allocation, not a deep copy.