Memory allocation of user defined type


#1

I am using an array of a type that I define, but this seems to take bigger memory than I have thought.
For example, if I check the memory allocated to ‘a = Int8[1,1,1]’, ‘Base.summarysize(a)’ gives 3 as expected.
But then I define a “test1” type by

type test1
    val::Int8
end

and then check the memory allocated to b = test1[test1(1), test1(1), test1(1)], Base.summarysize(b) gives 27, which on average costs 9 = 1+8 per element.

Moreover, If I use multiple types as follows:

type test2
    a::Int64
    b::Float64
    c::Bool
end

then Base.summarysize(test2(1,1.0,true)) gives 24, not Base.summarysize(1) + Base.summarysize(1.0) + Base.summarysize(true) = 17.

I am curious if this is a generic feature of Julia, or there is a way to fix this issue.


#2

What you are seeing is the fact that type creates a mutable struct. A mutable struct can’t be stored inline in an array and so we have to store a pointer to it, which on 64bit is an additional cost of 8 bytes.

immutable structs can be stored inline and so the the reported size is 3.

julia> type test1
           val::Int8
       end

julia> immutable test2
           val::Int8
       end

julia> b = test1[test1(1), test1(1), test1(1)]
3-element Array{test1,1}:
 test1(1)
 test1(1)
 test1(1)

julia> Base.summarysize(b)
27

julia> b = test2[test2(1), test2(1), test2(1)]
3-element Array{test2,1}:
 test2(1)
 test2(1)
 test2(1)

julia> Base.summarysize(b)
3

(Note in Julia 0.7, immutable types are simply structs, and mutable types are mutable structs)

See:


#3

Thank you very much for the reply!

I have a follow up question on immutable. If I compare

immutable test1
    a::Int64
    b::Float64
    c::Bool
end

and

type test2
    a::Int64
    b::Float64
    c::Bool
end

by checking the allocated memory, both Base.summarysize(test1(1,1.0,true)) and Base.summarysize(test2(1,1.0,true)) gives 24, not Base.summarysize(1) + Base.summarysize(1.0) + Base.summarysize(true) = 17.
When it comes to the memory allocated to the array of test1 and test2, test2 costs additional 8 bytes (on 64bit) of course.

Are there any way to make immutable struct that allocates 17 bytes of memory in this case?


#4

It would be hard in any language to allocate just 17 bytes, because the memory allocator itself will round up to some aligned multiple of a power of 2, so the minimum (if you were lucky, and on a 32-bit machine, might be 20 bytes, but I don’t think Julia would allocate that small a chunk [although I’m not sure]).
On 64-bit machines, Julia allocates at the minimum in multiples of 16 bytes.

Another thing, I wouldn’t depend at all on what summarysize reports, there is a lot that summary_size doesn’t count, which can be very important (for example, an empty Vector on a 64-bit machine I think takes a minimum of 64 bytes, but summarysize reports 0.

julia> x = Vector{UInt64}()
0-element Array{UInt64,1}

julia> Base.summarysize(x)
0

julia> @allocated(Vector{UInt64}())
80

#5

Got it! Thank you very much for the answer!!


#6

There are instances where allocating more memory is actually faster. I wouldn’t worry about these levels of micro-optimizations until you’ve actually measured it or have a hard limit you’re trying to satisfy with a very large array.