4.1.0 Before We Begin
After learning Rust’s general programming concepts, you’ve arrived at the most important topic in all of Rust—ownership. It’s quite different from other languages, and many beginners find it hard to learn. This chapter aims to help beginners fully master this feature.
This chapter has three sections:
- Ownership: Stack Memory vs. Heap Memory (this article)
- Ownership Rules, Memory, and Allocation
- Ownership and Functions
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
4.1.1 What Is Ownership?
Ownership is Rust’s most unique feature. It allows Rust to guarantee memory safety without a GC (garbage collector).
All programs must manage how they use computer memory while running. Some languages rely on garbage collection: while the program runs, they continuously look for memory that is no longer being used (for example, C#). In other languages, the programmer must explicitly allocate and free memory (for example, C/C++).
Rust is different from both of these. Rust uses an ownership system to manage memory. This system comes with a set of rules, and the compiler checks those rules at compile time. This approach produces no runtime overhead. In other words, ownership won’t slow your program down at runtime, because Rust moves the memory-management work to compile time.
4.1.2 Stack Memory (Stack) vs. Heap Memory (Heap)
In general, programmers don’t often think about the difference between stack memory and heap memory. For a systems programming language like Rust, whether a value is on the stack or on the heap has a much bigger impact on the language’s behavior and on some of the decisions you need to make.
While code is running, both the stack and the heap are available memory, but their structures are very different.
4.1.3 Storing Data
1. Stack Memory
The stack stores values in the order it receives them, and removes them in the opposite order (last in, first out, Last In First Out, abbreviated as LIFO).
Adding data is called pushing onto the stack (push), and removing data is called popping off the stack (pop).
All data stored on the stack must have a known, fixed size. In contrast, data whose size is unknown at compile time, or whose size may change at runtime, must be stored on the heap.
2. Heap Memory
The heap is less organized. When you put data on the heap, you request a certain amount of space. The operating system finds a chunk of space in the heap that is large enough, marks it as in use, and returns a pointer (the address of that space). This process is called allocating memory on the heap, and is sometimes shortened to “allocating”.
3. Pointers and Memory
Because a pointer has a fixed size, you can store the pointer itself on the stack. But if you want the actual data the pointer points to, you must use the address in the pointer to access it.
Pushing data onto the stack is much faster than allocating on the heap:
- On the stack, the operating system doesn’t need to search for space to store new data; that location is always at the top of the stack (the end of the stack)—that is, the beginning of the currently available stack memory.
- Allocating space on the heap requires more work: the operating system must first find a chunk of space large enough to hold the data, and then keep records so it can allocate again later.
4.1.4 Accessing Data
Accessing data on the stack is faster than accessing data on the heap, because you must follow a pointer to find data on the heap—an extra level of indirection. For modern processors, because of caching, the fewer jumps memory access needs to make, the faster it tends to be.
If data is stored closer together, the processor can work faster—for example, on the stack. Conversely, if the data is farther apart, processing can be slower—for example, on the heap (and allocating a large chunk of heap space also takes time).
4.1.5 Function Calls
When code calls a function, values are passed into the function (including pointers to data on the heap). The function’s local variables are pushed onto the stack. When the function ends, those values are popped off the stack.
4.1.6 Why Ownership Exists
The problems ownership solves:
- Tracking heap memory allocated by the code—in other words, tracking which parts of code are using which data on the heap
- Minimizing duplicate data on the heap
- Cleaning up unused data on the heap to avoid running out of space
Once you understand ownership, you won’t need to constantly think about the stack and the heap. But knowing that managing heap data is the reason ownership exists helps explain why it works the way it does.
Top comments (0)