Ownership: one owner, no garbage collector
GoByte Skills #11: Rust frees memory without a garbage collector because every value has exactly one owner. Move it and the old name is dead. When the owner's scope ends, the compiler has already written the drop call.
Piere is one of GoByte's characters. This post was drafted by AI agents in Piere's voice, then fact checked, run and edited by the GoByte team.
Each value has one owner and is freed when the owner goes out of scope, which is how Rust frees memory without a collector. Nothing scans the heap at runtime: the compiler decides, while compiling, the line where each value dies.
Transcript
Rust code types in while a value box moves from owner a to owner c, a second value moves into take and is dropped when that function ends, and the first is dropped at the closing brace of main.
struct Noisy(&'static str);
impl Drop for Noisy {
fn drop(&mut self) {
println!("drop {}", self.0);
}
}
fn take(n: Noisy) {
println!("take owns {}", n.0);
} // n's scope ends here
fn main() {
let a = Noisy("a");
let b = Noisy("b");
let c = a; // move: `a` is now unusable
take(b); // move into take
println!("main ends, c holds {}", c.0);
} // c's scope ends here
Output:
take owns b
drop b
main ends, c holds a
drop a
The mechanism#
let c = a is a move: the value's bytes are copied into c and the name a is dead. For a String those bytes are a pointer, a length and a capacity; the heap buffer stays put (same address, checked with as_ptr). Use a after the move and the build fails with E0382, "borrow of moved value: a". One live owner means exactly one place to free, so the compiler inserts the drop call at the end of that owner's scope. take(b) moved b into the function, which is why b died before main printed its last line.
Conditional moves#
In if flag { take(x) } the compiler cannot know statically whether x is still owned, so it keeps a hidden drop flag on the stack and checks it at the closing brace. Still no collector: one boolean.
Edges#
Copy types (integers, bool, shared references) are copied, not moved, so the original stays usable. Locals drop in reverse order of declaration. And dropping is not a promise: std::mem::forget is a safe function, and an Rc cycle never reaches a count of zero. Rust guarantees memory safety, not the absence of leaks.
Determinism#
The same rule closes files, releases locks and returns pooled connections at a line you can point to, not whenever a collector gets around to it. It is RAII, plus a compiler that refuses to let you touch the object after it is gone.
Rule of thumb#
For every value, you should be able to say who frees it and on which line. Rust does have a garbage collector. It runs at compile time and its name is the closing brace.
Your product here? Partner with us
Back to topDiscussion
No comments yet. Signed in GoByte members with a verified e-mail can join. Community guidelines
Reading is open to everyone. Commenting and voting need a GoByte account with a verified e-mail.