# Getting rid of memory allocations in nested functions

**URL:** <https://discourse.julialang.org/t/getting-rid-of-memory-allocations-in-nested-functions/93812>\
**Category:** Performance\
**Tags:** question, memory-allocation\
**Created:** [January 31, 2023, 9:09am UTC](https://discourse.julialang.org/t/getting-rid-of-memory-allocations-in-nested-functions/93812 "2023-01-31T09:09:53Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![p-gw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/p-gw/32/210518_2.png) [@p-gw](https://discourse.julialang.org/u/p-gw)\
**Post date:** [January 31, 2023, 9:09am UTC](https://discourse.julialang.org/t/getting-rid-of-memory-allocations-in-nested-functions/93812/1 "2023-01-31T09:09:54Z")

</div>

Hi,

I am trying to minimize memory allocations of a function in my package.  
However, it displays some mysterious behaviour - at least for me.  
Since there are many experts here, maybe somebody can shed some light on what’s going on here.

Here is a MWE of the problem:

I have an `outer!` function that modifies a vector `x` by calling an `inner` function on each element of `x`. Additionally a function is passed as an argument provided by the user:

```julia
function outer!(x, f=identity)
    for i in eachindex(x)
        x[i] += inner(f)
    end
end

function inner(f)
    y = zero(Float64)
    for i in 1:10
        y += f(1)
    end
    return y
end

```

If I call this version it results in a lot of allocations:

```julia
x = zeros(1000)
@benchmark outer!($x)

BenchmarkTools.Trial: 10000 samples with 1 evaluation.
 Range (min … max): 63.021 μs … 9.655 ms ┊ GC (min … max): 0.00% … 99.07%
 Time (median): 82.074 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 84.586 μs ± 207.426 μs ┊ GC (mean ± σ): 5.42% ± 2.21%

  ▄▂█▆▃▄▃▃ ▄▆▆▆▅▅▄▃▃▂▂▁▁▁ ▂
  ██████████▇▇▇████████████████████▇▇▇▇▇▇▇▇▆▆▄▆▅▃▅▄▅▂▅▄▄▂▄▃▅▄▄ █
  63 μs Histogram: log(frequency) by time 138 μs <

 Memory estimate: 54.52 KiB, allocs estimate: 3489.

```

Note that this only happens if `inner` has the `for` loop. if I define `inner` without the loop all allocations vanish.

However, if I just evaluate `f` in `outer!` once, the allocations also vanish:

```julia
function outer!(x, f=identity)
    f(1) # evaluate f once
    for i in eachindex(x)
        x[i] += inner(f)
    end
end

```

```julia
@benchmark outer!($x)

BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max): 71.814 ns … 5.371 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 72.181 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 76.442 ns ± 67.196 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▄▂▂▁ ▁ ▁
  ██████████████▇▇▇▆▇▆▆▇▆▆▅▆▅▆▆▅▆▅▅▄▅▄▄▅▅▅▅▆▅▄▄▄▄▅▄▄▄▄▃▄▄▄▁▄▄ █
  71.8 ns Histogram: log(frequency) by time 135 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

I am trying to understand what leads to the memory allocations in this case and why evaluating `f` a single time gets rid of them. I’m fine with leaving `f(1)` in my code, but it seems like a rather hacky solution and I’m sure there is a better way of solving this problem.

Hopefully somebody can help me here.

---

<div class="post-metadata">

**Author:** ![ademonts](https://avatars.discourse-cdn.com/v4/letter/a/ba8739/32.png) [@ademonts](https://discourse.julialang.org/u/ademonts)\
**Post date:** [January 31, 2023, 9:22am UTC](https://discourse.julialang.org/t/getting-rid-of-memory-allocations-in-nested-functions/93812/2 "2023-01-31T09:22:30Z")

</div>

When passing functions as arguments, it’s better to add the type parameter in the signature so it can specialize on whatever function `f` is :

```julia
function outer2!(x; f::F=identity) where F
    for i in eachindex(x)
        x[i] += inner(f)
    end
end

julia> @btime outer!($x)
  45.900 μs (3489 allocations: 54.52 KiB)

julia> @btime outer2!($x)
  52.487 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![p-gw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/p-gw/32/210518_2.png) [@p-gw](https://discourse.julialang.org/u/p-gw)\
**Post date:** [January 31, 2023, 9:29am UTC](https://discourse.julialang.org/t/getting-rid-of-memory-allocations-in-nested-functions/93812/3 "2023-01-31T09:29:58Z")

</div>

Well, that was a fast solution… Many thanks!

---

<div class="post-metadata">

**Author:** ![j-fu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/j-fu/32/11373_2.png) [@j-fu](https://discourse.julialang.org/u/j-fu)\
**Post date:** [January 31, 2023, 9:31am UTC](https://discourse.julialang.org/t/getting-rid-of-memory-allocations-in-nested-functions/93812/4 "2023-01-31T09:31:06Z")

</div>

See also the (admittedly slightly cryptic) remarks in the [Julia Performance Tipps](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing).
