C.W.K.
Stream
Lesson 01 of 05 · published

Stack, Heap, and Why Ownership Exists

~12 min · ownership, stack, heap, memory

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

Ownership is the one idea the entire language is built on. But to get why it exists, you need a clear picture of where your data lives: the stack or the heap.

The stack

The stack is fast and rigid. Values go on and come off in order (last in, first out), and every value must have a known, fixed size. An i32, a bool, a char — fixed size, lives on the stack, basically free to create and destroy.

The heap

The heap is flexible but slower. When you need a size that can grow — a String you'll append to, a vector that grows — the program asks the allocator for space on the heap and gets back a pointer. That pointer (fixed size) sits on the stack; the actual bytes live on the heap. Allocating and freeing heap memory has real cost, forgetting to free it is a leak, and freeing it twice is a crash.

Who frees the heap?

This is the question every language answers differently. C makes you call free() and punishes mistakes with crashes. Java and Python run a garbage collector that scans and frees later, paying at runtime. Rust's answer is ownership: each heap value has exactly one owning variable, and when that owner goes out of scope, the memory is freed — automatically, deterministically, with zero runtime collector.

Ownership is Rust's answer to 'who frees the heap?' Not you (C), not a runtime collector (Java) — the owner, at a compile-time-known moment. That single rule is the root of everything else in this quest.

Why you'll feel it everywhere

Stack values like i32 and bool are cheap to copy, so Rust copies them freely. Heap values like String are expensive and dangerous to copy implicitly, so Rust moves them instead — and that's the behavior you'll meet in the very next lesson.

Code

Stack values vs a heap-owning String·rust
fn main() {
    // Stack: fixed size, cheap. The whole value lives inline.
    let age: i32 = 42;
    let ready: bool = true;

    // Heap: String owns a growable buffer. The struct on the stack
    // holds a pointer + length + capacity; the bytes live on the heap.
    let mut name = String::from("Ferris");
    name.push_str(" the crab"); // may reallocate on the heap

    println!("{age} {ready} {name}");
} // `name` goes out of scope here -> its heap buffer is freed, once

External links

Exercise

List five values from a program you've written and label each 'stack' or 'heap': an integer counter, a user's name they typed at runtime, a fixed boolean flag, a list that grows, a single character. Why does the growable data have to live on the heap?
Hint
Anything whose size isn't known at compile time, or that can grow at runtime, needs the heap. Fixed-size scalars stay on the stack.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.