Jun 28, 2026

A Primer on Memory Rules in Rust

4 min read

Table of Contents

This is meant to be a short note on Rust's ownership and borrowing principles, and how they prevent the most common memory bugs from happening.

Stack and Heap

Before diving into memory management, we will quickly recall how the stack and heap work.

The stack and heap are parts of memory available at runtime, structured differently.

To push data onto the stack, data size must be known at compile time.

Data with an unknown size or a size that might change must be allocated on the heap, with a pointer to its heap address pushed onto the stack.

Ownership applies to all Rust values, but it's most visible with heap-allocated data, since Rust must know exactly when to free the heap allocations.

Ownership

Rust has three fundamental ownership rules, which govern how memory is managed:

  1. A value must have an owner
  2. A value must only have one owner
  3. When the owner goes out of scope, the value is dropped

fn main() {
  let p = String::new();
  let q = p; // owner is now q
} // q out of scope, value dropped

Single ownership makes the responsibility of freeing memory very clear, since multiple owners trying to free the same memory allocation is unsafe.

References and Borrowing

References allow callers to borrow data without taking ownership.

Due to non-lexical lifetimes, a borrow ends at its last use instead of at the end of its surrounding lexical scope.

The following are the rules of references that prevent common memory bugs from happening.

1. Either one mutable reference or multiple immutable references can exist for a value

This avoids aliasing bugs where one part of the code assumes a value is stable, while another part changes it underneath. Across threads, the single mutable reference rule also helps prevent data races.

2. References must always point to valid data

fn main() {
  let r;
  {
    let g = 2;
    r = &g; // compiler throws, since r outlives g
  }

  println!("{}", r);
}

This check prevents dangling pointers from being accessed, as the compiler rejects references that outlive their owner.

Conclusion

To sum it all up, we briefly talked about the stack and heap, covered the fundamentals of ownership and borrowing, and reasoned about how these rules can help mitigate common memory issues.