Theme
Q009. Does Rust ownership have a runtime cost?
Short Answer
Basic ownership checking usually adds no runtime owner tracking because it happens at compile time. That does not make all ownership-related operations free: values may be copied or moved, resources must be dropped, and control flow can require drop flags. Rc, Arc, RefCell, and locks add runtime costs only when those abstractions are selected.
Deep Dive
"Zero-cost" means Rust aims not to add bookkeeping beyond what equivalent correct low-level code needs. A String move may transfer a pointer, length, and capacity, while dropping it eventually calls the allocator. Those operations are real, but there is no extra tracing collector or ordinary owner registry.
Potential costs include:
- copying inline bytes for a move or
Copyoperation; - allocator and deallocator calls;
- destructor work and recursive drop glue;
- conditional branches for drop flags;
- reference-count updates for
Rc<T>and atomic updates forArc<T>; - runtime borrow or synchronization checks in types that explicitly provide them.
Optimization can eliminate many moves, copies, stack slots, and drop-flag branches when their effects are not observable.
Internal Model
Ownership analysis runs in the compiler. Generated code retains only the operations required by program semantics and the selected abstractions.
A moved value may never occupy two physical stack slots: the optimizer can keep it in registers, reuse one slot, pass it directly to a callee, or eliminate it entirely. Performance claims must therefore be verified on optimized code and with measurement.
Example
rust
fn main() {
let first_number = 42_i32;
let second_number = first_number; // independent Copy value
let first_text = String::from("rust");
let second_text = first_text; // ownership transfer
println!("{first_number} {second_number} {second_text}");
}Common Mistakes
- Interpreting "compile-time ownership" as "the program has no runtime costs."
- Assuming every source-level move becomes a machine-level copy.
- Blaming ownership for costs introduced by allocation, reference counting, or synchronization.
Follow-ups
- When can moving a large value be expensive?
- Why does
Arc<T>require atomic reference counting? - How can generated code be inspected and benchmarked correctly?
Related
- Q007. Is ownership related to whether a value is stored on the stack or the heap?
- Q008. How is ownership enforced and represented under the hood?
- Q010. How does ownership determine a value's lifetime?
References
- Rust Reference
- rustc-dev-guide
- The Rust Performance Book