πŸ”‘

Ownership & Borrowing β€” How Rust Manages Memory Without GC

The core rules that guarantee memory safety at compile time

C/C++ leaves memory management to the programmer. Mistakes cause use-after-free, double free, dangling pointers β€” 70% of security vulnerabilities come from here (Microsoft stats). Java/Go/Python solve this with garbage collectors (GC), but GC pauses and memory overhead follow.

Rust chose a third way. The compiler checks ownership rules to catch memory bugs at write time. Zero runtime cost.

Three Rules

1. Each value has exactly one owner. let s2 = s1; moves ownership from s1 to s2. Using s1 afterward is a compile error.

2. Borrowing comes in two flavors. &x is an immutable reference (multiple allowed), &mut x is mutable (only one). Can't have both simultaneously.

3. References can't outlive their owner. This is the lifetime rule, preventing dangling pointers at the source.

What's Hard at First

The frequency of compiler errors shakes your confidence. Especially when trying to put references in structs β€” the lifetime annotation requirement feels like a wall. But this is just bugs that "would explode at runtime" in other languages pulled forward to compile time. The error location changed, not the bug count.

Key Points

1

Every value has exactly one owner

2

When the owner goes out of scope, the value is automatically dropped (RAII)

3

Multiple immutable refs (&T) allowed, only one mutable ref (&mut T)

4

While a reference is valid, the owner can't move or mutably borrow the value

5

The compiler (borrow checker) statically verifies all these rules

Pros

  • Memory bugs caught at compile time β€” compile errors instead of runtime crashes
  • No GC β€” zero runtime overhead, predictable performance
  • Data race prevention β€” compiler blocks simultaneous mutable access

Cons

  • Steep learning curve β€” fighting the borrow checker is the initial hurdle
  • Self-referential structs are fundamentally impossible by default
  • Prototyping speed slower compared to GC languages

Use Cases

Systems programming β€” memory safety in OS kernels, drivers Web servers β€” predictable response times without GC pauses Embedded β€” writing code that runs on stack only, no heap allocation