 # Why does this allocate?

Consider the following code:

``````function foo(x)
if x > 0
(x, 1)
else
nothing
end
end
``````

It seems that this code has 1 allocation:

``````julia> bla = 
1-element Array{Int64,1}:
1

julia> @time foo(bla)
0.004369 seconds (1.32 k allocations: 98.988 KiB)
(, 1)

julia> @time foo(bla)
0.000003 seconds (1 allocation: 32 bytes)
(, 1)
``````

Why does this happen?
I am using Julia built from commit 39c278b728.

The allocation does not happen for either

``````function foo1(x)
if x > 0
(x, 1)
else
(x, 2)
end
end
``````

or

``````function foo2(x)
if x > 0
x
else
nothing
end
end
``````

Probably because the tuple ends up in global scope. If you do something like

``````julia> g(bla) = (foo(bla); nothing)
g (generic function with 1 method)

julia> @time g(bla)
0.000002 seconds
``````

it doesn’t allocate.

1 Like

Note that your code also allocates if we add @noinline to foo and @code_llvm foo(bla) shows that a call to jl_gc_pool_alloc is being generated.
Consider this slightly longer example:

``````struct Bla
x::Int
end

@noinline function Base.iterate(iter::Bla, state)
st, idx = state

if idx <= length(st)
return st[idx], (st, idx + 1)
else
return nothing
end
end

@noinline function Base.iterate(iter::Bla)
st = collect(1:iter.x)
idx = 1

return Base.iterate(iter, (st, idx))
end

function sumslow(bla::Bla)
n = 0

for x in bla
n += x
end

return n
end

Base.IteratorSize(::Type{Bla}) = Base.SizeUnknown()

Base.eltype(::Type{Bla}) = Int
``````

The @noinline is intentional since this is a reduced example and I do not want to force @inline for the project I am working on.
I get the following result:

``````julia> @btime sumslow(Bla(2^20))
12.555 ms (1048578 allocations: 40.00 MiB)
549756338176
``````

Without the @noinline, I get

``````julia> @btime sumslow(Bla(2^20))
1.950 ms (2 allocations: 8.00 MiB)
549756338176
``````

Does this happen due to an unrelated reason?

1 Like

In general, tuples that wrap heap-allocated objects might themselves have to be heap-allocated.

3 Likes

I thought so. I’m probably hitting a case where https://github.com/JuliaLang/julia/pull/33886 does not apply, right?

1 Like