Heap Memory

Returning variable-length values on the stack

Let's say we want a function to return a Vec.

fn get_years() -> Vec<i32> {
    return vec![1995, 2000, 2005, 2010, 2015];
}

let years = get_years();

If all we have is stack memory, this would be very difficult.

Remember, the way we return values is by having the caller reserve space up front for the return value, which the called function can then write into before returning. However, in this case the caller can't know how much space to reserve!

If the Vec being returned ends up being empty, the caller only needs to reserve enough space for the Vec's metadata struct. But it might not be empty - it might be enormous! Should the caller reserve a gigabyte of space just in case get_years happens to return an enormous Vec? That wouldn't scale - if we did that, calling a couple of functions that return Vecs would quickly run us out of stack space, leading to a Stack Overflow.

The heap

Of course, returning Vec values is something we'll want to do on a regular basis, so the approach of preallocating a huge amount of stack memory for them "just in case" won't work. We need a way to return values whose size we can't possibly know at runtime. This is where the heap comes in.

The actual way this call to get_years works is that all it returns on the stack is the VecMetadata struct we talked about previously:

struct VecMetadata {
    memory_index_of_first_element: usize,
    length: usize,
    capacity: usize,
}

Like all structs, this has a size that's hardcoded at compile-time. That means the caller can reserve exactly enough space to make room for this struct, and the function can return the Vec by writing its metadata into that space. The actual elements of the Vec aren't stored in the stack_bytes array at all. Instead, those elements are stored in the heap_bytes array.