Size of Heap Allocated Variable

I'm kind of curious as to the size of one of my variables, which is a vector of a primitive type. I found std::mem::size_of but that only seems to show what is allocated on the stack and does not actually show the memory usage of the vector, just the memory usage of the reference to the heap.

Is there a way to actually find out how much memory a vector variable uses?
Can the memory usage be calculated like the following, or is there something more going on in heap allocations?

fn memory_size<T>(v: Vec<T>) -> usize {
    v.len() * std::mem::size_of::<T>()
}

You'll probably want to use Vec::capacity() instead of Vec::len() here, but otherwise that should be correct: Vec keeps some allocated-but-unused space around so that it doesn't need to reallocate on every insert or delete.

1 Like

As @2e71828 said, use capacity() to get the size of the buffer allocated by Vec.

Is there a way to actually find out how much memory a vector variable uses?

Depending on your definition of "vector variable", if you want to include the pointer/lengths held by the Vec implementation itself and not just data, you'll need to add it to the capacity*element_length. E.g. playground

Also, there's a crate for that.

So if I have a more complex type with multiple vectors, including a two-dimensional vector, this would all need to programmed and calculated like that?

Is there really not a more precise method of doing this? It seems like it would be a problem for future maintainability where some code could stop working correctly if new properties are added to a struct.

So that crate implements these methods on some types, but as @qaopm mentions, I would have to manually add in the size of the stack allocation, since it doesn't seem like that crate does that (but it does for Box? I'm not sure I understand the comments in the crate).

Well, since it's called heap size…

Anyway, it didn't look like from your first post you were trying to automate heap and stack size counting. Vec::capacity() * size_of::<T>(), as you wrote it, doesn't account for the 3 * size_of::<usize>() bytes in the vector header, either.

stack size is irrelevant. the program allocates memory for the stack at the very beginning, i.e. the stack is similar to a vec, but it doesn't grow which is why stack overflows exist. you only need to care about dynamic memory allocation, because that isn't static.

The stack allocation size for every Vec is constant: 3 usize. Stack allocations are temporary, changing as call depth increases and decreases the number of active stack frames. Why would someone need to compute the stack allocation attributable to an item at runtime when it's predictable at the time that the program is conceptualized, before the first code is written?

On the other hand, heap allocation is variable and typically persists for varying amounts of time. That's why the emphasis in size computations is on the amount of allocated heap.

I based my answer on

Is there a way to actually find out how much memory a vector variable uses?

i.e. how much does the entire structure take. You can allocate vector on the heap and if you have a hashmap of vectors or a vector of vectors you'd eventually need to take them into account if you want to know the true size of the entire structure.

So how much memory does a hashmap take? Clearly it's the size of each entry times the number of occupied and unoccupied entries in the hashmap, plus some fixed overhead, including for the smart pointer on the stack that locates the hashmap that is necessarily on the heap since it can reallocate as entries are added.

Each entry needs to contain the key and the associated data (which in this case is the 3-usize smart pointer for the Vec). So how big is the key? What is the occupancy percentage of the hashmap? Have you taken all that heap memory into account?

Yes, for all containers you have to consider all internal structures. The original question was about a vector which is straightforward but for more complex containers like linked lists, hash maps, btree maps, etc one has too add all relevant implementation details.

Not sure there's an easy generic way of calculating those. Another consideration could be the item size itself, whether it's cow, (a)rc, etc.

The heapsize_derive crate contains a macro that will automatically generate a HeapSizeOf implementation for a custom type, if all its fields implement HeapSizeOf.

1 Like