Memory allocation of user defined type

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.

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:

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?

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

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

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.

3 Likes