In this lesson, you will learn how "reference cycles" can bypass Rust’s memory safety guarantees and cause memory leaks, even in otherwise safe code.
The Illusion of Safety
Up until now, we’ve relied on Rust’s ownership rules to clean up memory automatically when a variable goes out of scope. We learned that Rc<T> (Reference Counted) pointers manage memory by keeping a count of how many owners point to a value. When that count hits zero, the memory is dropped.
However, a memory leak occurs if we create a "cycle"—where two pieces of data hold Rc pointers to each other. Because they are both holding each other up, their reference counts will never drop to zero. The memory remains allocated, unreachable, and impossible for Rust to clean up.
Anatomy of a Cycle
Imagine two data structures, Node A and Node B. If Node A contains an Rc pointing to B, and B contains an Rc pointing to A, the system is locked:
use std::rc::Rc;
use std::cell::RefCell;
struct Node {
next: Option<Rc<RefCell<Node>>>,
}
// If we set Node A.next = Node B and Node B.next = Node A
// Both reference counts stay at 1 forever!
Even though this code is "safe" (it doesn't cause a segmentation fault or memory corruption), it is a logic error. The memory is "leaked" because your program has lost the ability to access or free it, and it will persist until the process terminates.
Why This Matters
In Rust, we prevent this by carefully managing our ownership architecture. If you find yourself needing to create cyclic structures (like a doubly-linked list or a graph), you must break the cycle. In later lessons, we would use a Weak<T> pointer, which allows a pointer to exist without increasing the reference count, effectively signaling: "I point to this, but I don't own it."
By understanding that reference cycles are the primary source of leaks in safe Rust, you learn to look for circular dependencies in your data structures.
Key Takeaway: Even in safe Rust, reference cycles between Rc pointers create "memory leaks" because the reference count never reaches zero, preventing the data from ever being dropped.