Deepcopy() of Dict has same mallocs as deepcopy() of Vector inside mutable Struct

I had a struct that had a Dict as one of its fields. I deepcopy the struct objects a lot, and that was the bottleneck in the program. I then realized that I could replace the Dict with a Vector, which I know has a smaller memory footprint (based on Base.summarysize()). However, after changing the Dict to a Vector the memory allocated is still the same, even though the number of allocations decreased. Could someone help explain this?

Code, Memory size (in bytes) and num allocations below:

The following is the output .mem file from julia -- track-allocation=user filename.jl

        - using Profile
        - 
        - small_n = 10
        - n = 100000
        - 
        - mutable struct MyStructWithDict
        0     d::Dict{Int, Int}
        -     i::Int
        - end
        - 
        - mutable struct MyStructWithVector
        0     d::Vector{Int}
        -     i::Int
        - end
        - 
        - function deepcopy_n_times(obj::MyStructWithDict, n::Int)
        0     for i in 1:n
 36800000         deepcopy(obj)
        -     end
        - end
        - 
        - function deepcopy_n_times(obj::MyStructWithVector, n::Int)
        0     for i in 1:n
 36800000         deepcopy(obj)
        -     end
        - end
        - 
        - example_dict = Dict{Int, Int}(2 => 2)
        - struct_dict = MyStructWithDict(example_dict, 1)
        - example_vec = Vector{Int}([2])
        - struct_vec = MyStructWithVector(example_vec, 1)
        - 
        - println("Size of Dict: ", Base.summarysize(struct_dict.d))
        - println("Size of Int: ", Base.summarysize(struct_dict.i))
        - println("Size of DictStruct: ", Base.summarysize(struct_dict))
        - println()
        - println("Size of Vector: ", Base.summarysize(struct_vec.d))
        - println("Size of Int: ", Base.summarysize(struct_vec.i))
        - println("Size of VectorStruct: ", Base.summarysize(struct_vec))
        - 
        - deepcopy_n_times(struct_dict, small_n)
        - deepcopy_n_times(struct_vec, small_n)
        - 
        - Profile.clear_malloc_data()
        - 
        - deepcopy_n_times(struct_dict, n)
        - deepcopy_n_times(struct_vec, n)

The output from the above print statements is

Size of Dict: 456
Size of Int: 8
Size of DictStruct: 472

Size of Vector: 48
Size of Int: 8
Size of VectorStruct: 64

When I replace the last two lines above with

@time deepcopy_n_times(struct_dict, n)
@time deepcopy_n_times(struct_vec, n)

I get:

0.106812 seconds (700.00 k allocations: 96.130 MiB, 7.34% gc time)
0.082474 seconds (400.00 k allocations: 47.302 MiB, 5.97% gc time)

which shows that the number of allocations has decreased, but the total memory hasn’t?

I’m pasting the same code as above in case you don’t want to deal with the output of the mem file:

using Profile

small_n = 10
n = 100000

mutable struct MyStructWithDict
    d::Dict{Int, Int}
    i::Int
end

mutable struct MyStructWithVector
    d::Vector{Int}
    i::Int
end

function deepcopy_n_times(obj::MyStructWithDict, n::Int)
    for i in 1:n
        deepcopy(obj)
    end
end

function deepcopy_n_times(obj::MyStructWithVector, n::Int)
    for i in 1:n
        deepcopy(obj)
    end
end

example_dict = Dict{Int, Int}(2 => 2)
struct_dict = MyStructWithDict(example_dict, 1)
example_vec = Vector{Int}([2])
struct_vec = MyStructWithVector(example_vec, 1)

println("Size of Dict: ", Base.summarysize(struct_dict.d))
println("Size of Int: ", Base.summarysize(struct_dict.i))
println("Size of DictStruct: ", Base.summarysize(struct_dict))
println()
println("Size of Vector: ", Base.summarysize(struct_vec.d))
println("Size of Int: ", Base.summarysize(struct_vec.i))
println("Size of VectorStruct: ", Base.summarysize(struct_vec))

deepcopy_n_times(struct_dict, small_n)
deepcopy_n_times(struct_vec, small_n)

Profile.clear_malloc_data()

deepcopy_n_times(struct_dict, n)
deepcopy_n_times(struct_vec, n)