`sizeof` on custom struct does not check fields

For any Julia variable, I wish to check how much memory it uses just to exist.
The docstring of sizeof states:
Size, in bytes, of the canonical binary representation of the given DataType T, if any. Or the size, in bytes, of object obj if it is not a DataType.
However:

using SparseArrays
julia> sizeof(rand(Float64,10,10))
800  # 10*10*8 bytes
julia> sizeof(sprand(Float64,10,10,0.1))
40
julia> sizeof(SparseMatrixCSC{Float64,Int})
40

Thus sizeof on a struct just returns the size of its type. Wouldn’t it make more sense to have a recursive call

sizeof(X ::SparseMatrixCSC{Tv,Ti}) where {Ti<:Integer, Tv} = 
    sizeof(SparseMatrixCSC{Tv,Ti}) + sizeof(X.colptr) + sizeof(X.rowval) + sizeof(X.nzval)

?

Is this functionality implemented in another function? Also, how would it be possible to capture the size of arrays of pointers (other than manual sum(sizeof(x) for x in xx))?

julia> sizeof([[1,2,3,4,5],[6,7,8],[9,10]])
24  # should be 80 = (5+3+2)*8

Use:

help?> Base.summarysize
  Base.summarysize(obj; exclude=Union{...}, chargeall=Union{...}) -> Int


  Compute the amount of memory, in bytes, used by all unique objects reachable
  from the argument.

  Keyword Arguments
  ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

    •  exclude: specifies the types of objects to exclude from the
       traversal.

    •  chargeall: specifies the types of objects to always charge the
       size of all of their fields, even if those fields would normally
       be excluded.

  See also sizeof.

  Examples
  ≡≡≡≡≡≡≡≡

  julia> Base.summarysize(1.0)
  8
  
  julia> Base.summarysize(Ref(rand(100)))
  848
  
  julia> sizeof(Ref(rand(100)))
  8
4 Likes

Yep it’s summarysize you want.

sizeof is only useful to most users for bits types and is the same as summarysize on these. Other types do not have a defined layout so their sizeof is exposing internal implementation details.

Why do I get

julia> Base.summarysize([[1,2,3,4,5],[6,7,8],[9,10]])
264

julia> Base.summarysize(rand(Float64,10,10))
840

julia> Base.summarysize(sprand(Float64,10,10,1.0))
1848

instead of 80, 800, 800+800+88 (rowval, nzval, colptr) respectively? Where is this hidden memory consumption?

Part is the array header which contains e.g. the size of the array and the dimensions. You can check the size of an empty array is actually 40.
This explains your second example exactly and accounts for most of the memory of the other examples. In case of the sparse array there are 2 more fields in the struct for the size I think.

2 Likes