简体   繁体   中英

Memory sizes (in bytes) of vector iterator, vector chain, and vector flatten in Rust

I have the following example code:

let vector_1 = vec![1, 2, 3];
let vector_2 = vec![4, 5, 6];

{ 
  let vector_1_iter = vector_1.iter(); 
}
{ 
  let chained = vector_1.iter().chain(vector_2.iter());
}
{
  let vector_combined = vec![vector_1, vector_2];
  let flatten = vector_combined.iter().flatten();
}

I want to know the sizes of vector_1_iter, chained, flatten in bytes. If I was finding the sizes of vector_1 and vector_2, I would just take the length of the vector and multiply it by the bytes of i32. However, I'm not sure whether the size would change after converting the vector into an iterator. Same with chaining and flattening, would they not take up the same size equal to the entire length of the array times the size of each data type?

Size of Vec

Vec is a struct, made up of a pointer to an area of memory allocated on the heap, a capacity (showing the total number of items which could be stored in the heap memory, and a length (showing the number of items that are currently stored in the heap memory).

Each of these is of type usize - which occupies 8 bytes on an x86_64 architecture.

Therefore the total memory occupied by a Vec<i32> is actually 24 bytes + (capacity x 4). Or, more generally:

std::mem::size_of::<Vec<T>>() + vector_1.capacity() * std::mem::size_of::<T>()

Size of iterator

Note that this:

let vector_1_iter = vector_1.iter(); 

does not actually convert vector_1 into an iterator - iter borrows the vector, and returns a std::slice::Iter which references it. It doesn't have any extra heap allocation associated with it, we can see it's memory size like this:

println!("size of vector_1_iter {}", std::mem::size_of::<std::slice::Iter<'_, i32>>());

The result is 16 bytes, on my machine.

Size of chained iterators

When we use chain to chain together two iterators, both of the iterators are consumed, and a std::iter::Chain is returned. We could use size_of again, but this starts to get a little more tricky to express when there are multiple levels of generic parameters. Instead we can use std::mem::size_of_val :

let chained = vector_1.iter().chain(vector_2.iter());
println!("size of chained iter {}", std::mem::size_of_val(&chained));

On my machine this prints 32 - which makes sense, since it is housing both of the original iterators (each of which was 16 bytes).

Flattened Iterator

We can use the same method:

let vector_combined = vec![vector_1, vector_2];
let flatten = vector_combined.iter().flatten();    
println!("size of flattened iter {}", std::mem::size_of_val(&flatten));

This prints 48 for me.

Rust Playground


Note that none of the iterators above consumed the original containers they were iterating over. If you had used into_iter() the result would be quite different, because this method consumes the Vec and returns an IntoIter struct - so it then owns the heap memory which contains the actual contents of the Vec .

Also note that the contents and layout of these structs are implementation details, so you can't really rely on these sizes being constant. Vec is a bit of an exception, because there are some guarantees made about its structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM