In debug builds, there will be a shallow memcpy in and out on every closure. The HashMap’s main (heap) data is untouched, but it will copy size_of::<HashMap<String, u8>>()
many bytes, which are the pointers and other metadata that are part of the HashMap value on the stack, not any data on the heap. Let’s see what that is…
use std::mem::size_of;
use std::collections::HashMap;
fn main() { dbg!(size_of::<HashMap<String, u8>>()); }
[src/main.rs:3] size_of::<HashMap<String, u8>>() = 48
So there you have it, it copies 48 bytes on the Rust playground (in current stable rust), which are 6 machine words (in the Rust playground, which is 64-bit).
…this post is edited after I learned that 48/8 is not 4…
But you shouldn’t worry about debug builds; Rust’s monomorphization means that in an optimized build, there will most likely be no copying at all. And even if it copies 6 words between stack frames twice per iteration, that’s most likely negligible compared to allocating and filling the string, and inserting into the map. In particular, calling insert
will probably read these 4 words that make up (the outer / shallow layer of) the HashMap multiple times, too, and follow all the pointers, etc…
For completeness let’s look at what these 48 bytes / 6 words actually represent. HashMap is implemented in the hashbrown crate, here, consisting of the hasher, and a “RawTable”, and it also talks about an “allocator”. The allocator is actually a zero-sized struct (in the default case), and the hasher contains a key of two u64
s. The raw table contains the remaining 4 words; apparently 3 usizes and one pointer, as defined here. The pointer points (in)to the HashMap’s heap data, and the usize values keep track of the size, the number of items, and the number of items that still can be added before a resize. (Sounds like it might be slightly redundant, but perhaps it’s more efficient than to try working just with 2 usize values.)
So that’s what’s getting copied when you move a HashMap
, 2 u64s, 3 usizes, and 1 pointer. (All of this is of course subject to change; HashMap could at any point be changed to be slightly more than 6 or slightly less than 6 words; it most likely won’t ever be changed to be significantly larger than 6 words.)