# Unexpected allocation

**URL:** <https://discourse.julialang.org/t/unexpected-allocation/109393>\
**Category:** Performance\
**Created:** [January 29, 2024, 12:31pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393 "2024-01-29T12:31:52Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![abraunst](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraunst/32/6880_2.png) [@abraunst](https://discourse.julialang.org/u/abraunst)\
**Post date:** [January 29, 2024, 12:31pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/1 "2024-01-29T12:31:52Z")

</div>

I’m trying to write an iteration for my type. The iteration needs to keep a `Vector` and an `Int` in its state. I cannot get rid of an allocation.

I condensed the problem into the following MWE:

```julia
function iter((i,v))
    v[i] += 1
    i == length(v) ? nothing : (i+1,v)
end

```

which gives:

```julia
julia> state=(1,[1,2]); @btime iter($state);
  3.805 ns (1 allocation: 32 bytes)

```

Is there any way to get rid of this allocation? Thanks a lot for any insight!

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 29, 2024, 1:01pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/2 "2024-01-29T13:01:02Z")

</div>

I don’t understand that allocation either, but I have a similar iterator, which does not allocate. Here is a simplified version of it:

```julia-repl
julia> struct Chunk{T<:AbstractArray}
           x::T
           n::Int
       end

julia> function iterate(c::Chunk, state=nothing)
           if isnothing(state)
               return (c, 1)
           elseif state < c.n
                return (c, state + 1)
           end
           return nothing
       end
iterate (generic function with 2 methods)

julia> @btime iterate($c)
  1.468 ns (0 allocations: 0 bytes)
(Chunk{Vector{Int64}}([1, 2], 1), 1)

```

---

<div class="post-metadata">

**Author:** ![abraunst](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraunst/32/6880_2.png) [@abraunst](https://discourse.julialang.org/u/abraunst)\
**Post date:** [January 29, 2024, 1:08pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/3 "2024-01-29T13:08:11Z")

</div>

Thank you for the reply!

It seems that it does allocate after the first iteration for me though:

```julia

julia> c = Chunk([1,2,3], 3)
Chunk{Vector{Int64}}([1, 2, 3], 3)

julia> @btime iterate($c)
  1.893 ns (0 allocations: 0 bytes)
(Chunk{Vector{Int64}}([1, 2, 3], 3), 1)

julia> @btime iterate($c,1)
  3.595 ns (1 allocation: 32 bytes)
(Chunk{Vector{Int64}}([1, 2, 3], 3), 2)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 29, 2024, 1:19pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/4 "2024-01-29T13:19:14Z")

</div>

I don´t know. Seems to be some artifact of benchmarking? In a “real” test it does not allocate:

```julia-repl
julia> using ChunkSplitters

julia> x = rand(1000);

julia> function test(x)
           s = 0.0
           for inds in chunks(x; n = 100)
               for i in inds
                   s += x[i]
               end
           end
           return s
       end
test (generic function with 1 method)

julia> test(x)
509.1937895395777

julia> @btime test($x)
  716.511 ns (0 allocations: 0 bytes)
509.1937895395777

```

The exact implementation of that is here: [ChunkSplitters.jl/src/ChunkSplitters.jl at 6f7ea5e8baf4b0de84f6d04e4320959c4c3f6f6a · m3g/ChunkSplitters.jl · GitHub](https://github.com/m3g/ChunkSplitters.jl/blob/6f7ea5e8baf4b0de84f6d04e4320959c4c3f6f6a/src/ChunkSplitters.jl#L107)

One difference, relative to the benchmark, is that in the “real” test the return value of the function to the REPL is always of the same type, while in the small example it can return `nothing` to the REPL. That may cause an artificial allocation, maybe.

---

<div class="post-metadata">

**Author:** ![abraunst](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraunst/32/6880_2.png) [@abraunst](https://discourse.julialang.org/u/abraunst)\
**Post date:** [January 29, 2024, 1:43pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/5 "2024-01-29T13:43:59Z")

</div>

You’re right! Unfortunately, in my case the allocation is real. I must have condensed the wrong MWE. Thanks again!

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [January 29, 2024, 9:01pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/6 "2024-01-29T21:01:36Z")

</div>

You could try to slap a `@inline` in front of your iteration functions. Sometimes that fixes allocations (which might stem from tuple packing/unpacking or so…)

---

<div class="post-metadata">

**Author:** ![abraunst](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraunst/32/6880_2.png) [@abraunst](https://discourse.julialang.org/u/abraunst)\
**Post date:** [January 29, 2024, 11:21pm UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/7 "2024-01-29T23:21:43Z")

</div>

Yeah, indeed this misteriously works!

Thanks @abraemer 🙂

A

---

<div class="post-metadata">

**Author:** ![abraunst](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraunst/32/6880_2.png) [@abraunst](https://discourse.julialang.org/u/abraunst)\
**Post date:** [January 30, 2024, 8:45am UTC](https://discourse.julialang.org/t/unexpected-allocation/109393/8 "2024-01-30T08:45:33Z")

</div>

> [@lmiq](#):
>
> One difference, relative to the benchmark, is that in the “real” test the return value of the function to the REPL is always of the same type, while in the small example it can return `nothing` to the REPL. That may cause an artificial allocation, maybe.

This is what I thought at first, but `iterate(x::Vector)` does not allocate, even if it can return `nothing`. So it seems that inlining definitely has also to do with it…
