[Avg. reading time: 6 minutes]
Ownership
Ownership is the core feature that makes Rust memory-safe without a garbage collector.
- It is not just a memory rule.
- It is the foundation of Rust’s design.
Memory Management Landscape
C / C++
- No garbage collector
- Very fast and predictable
- Developers must manually free memory
- Risk of leaks, double free, dangling pointers
Example: malloc() and free()
Python, Java, Go
- Use a garbage collector
- Memory automatically reclaimed
- Easier developer experience
- Runtime overhead and unpredictability
Garbage Collector runs during program execution.
Rust
- Combines C-like performance with automatic memory safety
- Uses compile-time ownership rules instead of a garbage collector
- Determines at compile time where values are dropped
- Enforces strict coding rules through the borrow checker
Rust Ownership System
-
Every value in Rust has an owner.
-
There can only be one owner at a time.
-
When the owner goes out of scope, the value is dropped.
-
Memory cleanup is deterministic and predictable.
-
Ownership is enforced at compile time.
-
Drop occurs automatically at the end of scope.
fn main(){ let x = 5; let y = 5; println!("owner x {}->{:p}", x,&x); println!("owner y {}->{:p}", y,&y); }
Example to show how variables goes out of scope and frees memory.
fn main() { { let s = String::from("Hello"); println!("{}", s); } // s goes out of scope here and is dropped println!("{}", s); }
No GC involved.
Printing Memory Addresses
{:p} is the pointer formatting specifier.
It prints the memory address of a reference.
Example:
fn main() { let x = String::from("Rachel"); println!("Stack address of x: {:p}", &x); let x = 5; // shadowing println!("Stack address of new x: {:p}", &x); }
- Shadowing creates a new binding
- The second x lives at a different stack address
- The first x is dropped before the new x becomes active
// Demonstrate Heap Pointer fn main() { let s = String::from("Rachel"); println!("Stack address: {:p}", &s); println!("Heap pointer : {:p}", s.as_ptr()); }