memtrace

Memory regions

  • Stack Memory
  • Heap Memory
  • Static Memory

Ownership model

  • Ownership & Moves
  • Borrowing & References
Open the Playground
VisualizersBorrowing & References

Borrowing & References

How shared and mutable references point at a value without owning it

What's happening · 01 / 10

Before anything runs

The compiled program has been loaded into memory, but no function has run yet. Nothing is on the stack and nothing is on the heap

Code

1fn main() {
2 let mut s = String::from("hi");
3 let r1 = &s;
4 let r2 = &s;
5 println!("{r1} {r2}");
6 let m = &mut s;
7 m.push('!');
8}

Borrowing & References

How shared and mutable references point at a value without owning it

HIGH ADDRESSESStackframes and localsHeapBox, String, Vec dataStatic datastatics, string literalsCodecompiled machine codeLOW ADDRESSES
Where this lives in a running program
BORROWSOWNERr1&xr2&xxi32 = 5READ ONLY
The idea in one picture

Step by step

Key takeaways

  • A reference points at a value without owning it
  • Many shared borrows or one mutable borrow, never both at once
  • A borrow ends at its last use
  • Dropping a reference never frees the data it points to

Resources

  • The Rust Book: References and borrowingThe borrowing rules this example walks through
  • Error code E0502Mixing shared and mutable borrows
  • The Rust Book: Validating references with lifetimesHow the compiler proves a reference never outlives its data

Research notes

  • Borrows ending at their last use is called non-lexical lifetimes (NLL), stable since Rust 2018
  • &mut is really about exclusive access; Cell and RefCell allow changing data through a shared & reference
  • r1 and r2 point at s on the stack, not at the heap buffer, so reading through them follows two pointers
  • Growing a String from capacity 2 jumps straight to 8, because the standard library uses a minimum capacity of 8 for 1-byte elements
stdoutempty

$cargorun// waiting for the first println!

Auto-play steps