✨🥞 Rust Visualized: The Stack, the Heap, and Pointers

The part of your operating system that allocates memory for a program as well as loading its code and data into memory is called a loader.

The loader defines four different areas of memory for a program: code, static, stack, and heap.

The static segment contains global variables, the code segment contains machine code, and the stack segment contains local variables that are defined inside functions.

When the function foo goes on the call stack, its stack frame must store foo's arguments, local variables, and return address.

The memory layout of a stack frame is fixed, so the size of variables needs to be known at compile time. The size of variables on the stack cannot grow or shrink.

Stacks are a simple but common data structure. Like a pile of pancakes, the last pancakes that go on a stack are the first pancakes to leave the stack. When you add to a stack, you always add to the top.

The call stack consists of stack frames, which contain arguments, local variables, and return addresses. Let's look inside the stack frame on the call stack when main is called.

If we look inside the stack frames on the call stack when foo(y) is called, we notice that the arguments, local variables, and variable addresses of foo have been added to the top of the stack.

The heap is dedicated to variables whose size is not known at compile time. You have a lot more freedom with variables stored on the heap, but you lose speed. You can control the lifetime of variables on the heap as well as assign them an arbitrary size.

In Rust, you can allocate memory on the heap using types like Box or Vec.

A Box<T> stores a pointer to heap data on the stack. The type of this Box is type T.

Pointers are an important concept, because we often reference variables in Rust using & syntax. When you reference a variable, you are pointing to that variable's location in memory.