Published on

Heap allocations in Rust

Authors

Heap allocation refers to allocating memory on the heap, which is an area of memory managed by the operating system. I will be focusing on Box< T > and Vec< T > methods in this post.

Before we start, let me quickly introduce stack and heap memory in Rust as we will be usnig this term throughout the blog.

  1. Stack: The stack is a region of memory where function calls and local variables are stored. It follows a LIFO(last-in-first-out) order, and the size of memory allocated on the stack is determined at compile time.
  2. Heap: The heap is a region of memory that allows for dynamic memory allocation. It doesn't have a specific order for memory allocation, and the size of memory allocated on the heap can be determined at runtime.

Heap Allocation method:

Box< T >

The Box< T > type provides a way to allocate memory on the heap and store a single value of type T. When you use Box< T >, you're essentially creating a pointer to a heap-allocated value of type T. This means that when the Box< T > goes out of scope, it will automatically deallocate the memory it owns. Please note, deallocation is performed by Rust's ownership system and not explicitly by Box< T > itself.

Declaration:
let value: i32 = 42;
let boxed_value: Box< i32 > = Box::new(value);
Before Heap Allocation
+-------+-------+
| Stack | Heap  |
+-------+-------+
After heap allocation with Box< T >:
+-------+-------+
| Stack | Heap  |
+-------+-------+
            |
            v
          +---+
          | T |
          +---+

Vec< T >

The Vec< T > type is used when you need a dynamically resizable array. It allocates memory on the heap to store a sequence of values of type T. The Vec< T > type is responsible for managing the resizing and reallocation of memory when elements are added or removed from the vector. It handles the bookkeeping and provides convenient methods for working with dynamic arrays. Also to note here, the actual deallocation of memory is performed by Rust's ownership system based on the ownership rules.

Declaration:
let values: Vec< i32 > = vec![1, 2, 3, 4, 5];
Before Heap Allocation
+-------+-------+
| Stack | Heap  |
+-------+-------+
After heap allocation with Vec< T >:
+-------+-------+
| Stack | Heap  |
+-------+-------+
            |
            v
    +---+---+---+---+---+
    | T | T | T | T | T |
    +---+---+---+---+---+

In Rust, ownership and borrowing rules ensure memory safety. The ownership model guarantees that there is always exactly one owner for each heap-allocated resource, and when the owner goes out of scope, the memory is automatically deallocated.

This seems to be a good point to start learning more about Rust's ownership system. I might write my own understanding of it but for now, Rust has a very good explanation.