Understanding memory management in Rust


I really want to clearly understand memory management in Rust. So far I read the Chapter 6. Pointers and Memory Safety of the book Rust Essentials on the subject. But I find that it is not enough.

I really would like to understand the concept of ownership and borrowing. So far, I think I am not so bad on these two. But I would like to know more about the different pointers like:

  • Box
  • Rc
  • Arc

I don't understand how can I use them well. References on the subject would be appreciated.

If you haven't read this, it's a good explanation of Box: The Stack and the Heap.

As for Rc and Arc, I don't know of a good guide for them, but I could try to explain them simply in terms of what they do.

Rc and Arc are (atomic) reference counted pointers, and act as an escape of the borrowing system. It puts the inner contents on the heap, like Box, but instead of using compile-time calculated lifetimes/scopes to determine when the data should be dropped, it keeps track of how many people have pointers to the data at runtime.

Arc/Rc are very useful for when you are storing data which you want to have access to from completely separate structs, and you really don't know at compile time which struct will be dropped first. So, instead of finding out when to be dropped at compile time, whenever you use .clone() on an Arc/Rc, it increments a "reference count" inside of itself and returns a new Arc/Rc pointing to the same data. When all cloned Arc/Rcs and the original Arc/Rc are dropped, the data is dropped, but if any are still being used it waits until they are all dropped.

Arc/Rc do have the restriction of not allowing any mutability however. Because they manually find out who is referencing the data at runtime, they don't know at compile time if the reference you own is the only one with access to the data, so they don't allow any mutability. To get mutability with Arc/Rc, you'll want to use either Cell, RefCell (non-threadsafe), or Mutex or RWLock (threadsafe) depending on your needs and data type.

One last note: I've referred to/explained Rc and Arc at the same time, because they are basically exactly the same. The only difference is that Arc uses atomic variables to achieve thread safety, while Rc doesn't. There's a slight increase in overhead in using Arc, but Rc doesn't support use between threads.

Also I stumbled upon a wonderful blog post about wrapper types in Rust you may want to read: Wrapper Types in Rust: Choosing Your Guarantees - In Pursuit of Laziness
It tells a lot about different wrapper types, like Box, Arc etc in a well structured manner.

Thank you @daboross and @kstep.

I had to dig the subject and do some experimentation to understand. It is not easy at first but I am getting better. I am at a point where my technical understanding is pretty good but I still have difficulties to think naturally about how I should manage memory in my code and how I should use composition with different pointer types. I guess I will get better with time.