# Common allocation mistakes

**URL:** <https://discourse.julialang.org/t/common-allocation-mistakes/66127>\
**Category:** Performance\
**Tags:** memory-allocation\
**Created:** [August 10, 2021, 12:08pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127 "2021-08-10T12:08:19Z")\
**Posts on this page:** 20\
**Page:** 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:** [August 11, 2021, 10:20am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/21 "2021-08-11T10:20:02Z")

</div>

> [@amrods](#):
>
> Is there any tool that allows me to see where allocations are happening?

> **[Tracking allocations · JuliaNotes.jl](https://m3g.github.io/JuliaNotes.jl/stable/memory/)**
>
> Documentation for JuliaNotes.jl.

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [August 12, 2021, 11:07am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/22 "2021-08-12T11:07:09Z")

</div>

Question, in function that create arrays inside of them, it is better to pass those arrays as arguments? For example:

```julia
function f1(x)
    sto = similar(x)
    sto = x .+ 1
    return sto
end

function f2(sto, x)
    sto = x .+ 1
    return sto
end

```

So that in a loop I can reuse `sto` without Julia having to allocate memory for every iteration:

```julia
function g1(x)
    for i in 1:100
        sto = f1(x)
    end
end

function g2(x)
    sto = similar(x)
    for i in 1:100
        f2(sto, x)
    end
    return sto
end

```

is that the point?

---

<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:** [August 12, 2021, 11:14am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/23 "2021-08-12T11:14:50Z")

</div>

Yes, usually what I do is to let this as an alternative to the user, like this:

```julia
function f1(x;aux=similar(x))
    aux .= x .+ 1 # note the broadcasting here!
    return aux
end

```

Then the function can be called only with `x`, in which case it allocates `aux`, or you can pass `aux` as a keyword parameter, in which it reuses what is given.

@amrods note that you need `.=` to broadcast, otherwise the preallocated vector is not used for anything (this is incorrect in the code you posted there).

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [August 12, 2021, 11:15am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/24 "2021-08-12T11:15:57Z")

</div>

oh nice, i didn’t know you could reference other arguments at function definition.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 12, 2021, 12:48pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/25 "2021-08-12T12:48:17Z")

</div>

> [@amrods](#):
>
> `A .= rand(size(A)...)`

> [@stillyslalom](#):
>
> `v .= rand.()`

There is also `Random.rand!` which will fill the array with random values, and also make sure that they have the correct eltype. For example

```julia
A = rand(Int8, 3, 4);
rand!(A)

```

`rand!` will generate random `Int8` values, etc.

---

<div class="post-metadata">

**Author:** ![TI36XPro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ti36xpro/32/33658_2.png) [@TI36XPro](https://discourse.julialang.org/u/TI36XPro)\
**Post date:** [January 22, 2022, 2:48pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/26 "2022-01-22T14:48:25Z")

</div>

These are great tips - thank you for writing this.

Once thing I recently learned related to views - and if I get any of this wrong please someone correct me - is that a view still allocates. For example, if you have a hot inner loop where you use small blocks of a larger vector you might think (or at least I naively did) that you can avoid heap allocations by using something like the following. I _thought_ I could use the view to do allocation-free access and operations on elements of `A`.

```julia
A = rand(100)
B = rand(3)
function view_test(A, B)
    tmp = @view A[2:4]
    tmp .= tmp .* B
end

```

This is a silly example, but in my own hot inner loop I was reusing that view in places many times and re-creating each iteration of the loop. I ended up with tons of heap allocations everywhere that view was used (sorry if this is obvious to others!). I eventually found some posts indicating that if you have something like this you should just loop over the small block - which is what I ended up doing. In other locations with larger arrays I got around the problem by using `copyto!` or just made loops there as well.

---

<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 22, 2022, 2:59pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/27 "2022-01-22T14:59:14Z")

</div>

That specifically should not allocate. But you can have allocations with views if the slice is of a non-contiguous memory block (not sure if this is true, what certainly happens is that views of non-contiguous slices are not very performant).

---

<div class="post-metadata">

**Author:** ![TI36XPro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ti36xpro/32/33658_2.png) [@TI36XPro](https://discourse.julialang.org/u/TI36XPro)\
**Post date:** [January 22, 2022, 3:03pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/28 "2022-01-22T15:03:18Z")

</div>

I get this when using `@btime`: `20.160 ns (1 allocation: 48 bytes)`

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [January 22, 2022, 3:32pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/29 "2022-01-22T15:32:16Z")

</div>

What I obtain:

```julia
julia> @btime view_test($A, $B);
  169.941 ns (0 allocations: 0 bytes)

```

Perhaps you didn’t interpolate the variables?

```julia
julia> @btime view_test(A, B);
  195.690 ns (1 allocation: 48 bytes)

```

I’m amazed at how fast your system is btw

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [January 22, 2022, 7:16pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/30 "2022-01-22T19:16:38Z")

</div>

Which version of Julia are you using?

In older versions (1.0 for sure, then I don’t remember), `struct`s with mutable members were heap-allocated. In the current stable and LTS versions (1.7 and 1.6, respectively), views should be stack-allocated but of course the stack-allocated data includes a reference to a heap-allocated backing array (except, of course, the cases when the backing array itself has `isbits` type, e.g. `UnitRange` or `StaticArray`).

---

<div class="post-metadata">

**Author:** ![TI36XPro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ti36xpro/32/33658_2.png) [@TI36XPro](https://discourse.julialang.org/u/TI36XPro)\
**Post date:** [January 22, 2022, 8:19pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/31 "2022-01-22T20:19:15Z")

</div>

I’m using 1.6.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 22, 2022, 9:53pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/32 "2022-01-22T21:53:38Z")

</div>

Even with variable interpolation?

1.6.3:

```julia
julia> @btime view_test($A,$B)
  80.945 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![TI36XPro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ti36xpro/32/33658_2.png) [@TI36XPro](https://discourse.julialang.org/u/TI36XPro)\
**Post date:** [January 23, 2022, 12:45am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/33 "2022-01-23T00:45:46Z")

</div>

Yes, interpolating then the allocation is zero.

What does that mean then? Where is the allocation coming from when you don’t interpolate?

---

<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 23, 2022, 1:13am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/34 "2022-01-23T01:13:07Z")

</div>

It is like the input variables were non-constant globals. See: [julia - When to interpolate in benchmarking expressions - Stack Overflow](https://stackoverflow.com/questions/57314092/when-to-interpolate-in-benchmarking-expressions)

(I miss as well a more in depth explantation of these interpolations in BenchmarkTools, as a rule of thumb I understand that they should be always used)

---

<div class="post-metadata">

**Author:** ![TI36XPro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ti36xpro/32/33658_2.png) [@TI36XPro](https://discourse.julialang.org/u/TI36XPro)\
**Post date:** [January 23, 2022, 1:41am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/35 "2022-01-23T01:41:30Z")

</div>

Ah okay - so the point then is that the view _did not_ create an allocation, it was just a mistake in how I was using `@btime`.

---

<div class="post-metadata">

**Author:** ![TI36XPro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ti36xpro/32/33658_2.png) [@TI36XPro](https://discourse.julialang.org/u/TI36XPro)\
**Post date:** [January 23, 2022, 1:56am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/36 "2022-01-23T01:56:53Z")

</div>

Just one more follow-up that I just remembered. I think allocation still may have been happening, in my particular case. I say this because I would use `julia --track-allocation=user` and `Profile` (making sure to clear the profiler before running the function) and I would see memory allocations next to the lines with views. Perhaps it was because they were views of non-contiguous sections of memory as you said in an earlier post.

---

<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 23, 2022, 2:15am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/37 "2022-01-23T02:15:58Z")

</div>

I tried to get allocations in those cases here, without success. Thus, I’m not sure if that still applies (or has anytime after 1.5). But it may.

At the same time I always found the output of `--track-allocation=user` confusing, I usually check [manually](https://m3g.github.io/JuliaNotes.jl/stable/memory/) the code after profiling with that to be sure of the source of the allocations.

---

<div class="post-metadata">

**Author:** ![alfaromartino](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alfaromartino/32/52986_2.png) [@alfaromartino](https://discourse.julialang.org/u/alfaromartino)\
**Post date:** [June 27, 2023, 4:09pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/38 "2023-06-27T16:09:09Z")

</div>

One more approach for the case 2. to avoid allocations when broadcasting. The package `LazyArrays` allows you to do this and keep the notation simple: it only requires adding `@~` to the broadcast, and you don’t need to pre-allocate the output.

Example:

```julia
using BenchmarkTools, LazyArrays
x,y = rand(100), rand(100)
tmp = similar(x)

#pre-allocating tmp
function f(x,y,tmp)
         z = 0.
         for i in 1:10
           @. tmp = x * y
           z += sum(tmp) 
         end
         z
end
@btime f($x,$y,$tmp) # 144.617 ns (0 allocations: 0 bytes)

#using LazyArrays
function g(x,y)
  z = 0.
  for i in 1:10
    tmp = @~ x .* y
    z += sum(tmp) 
  end
  z
end

f(x,y,tmp) == g(x,y) # true
@btime g($x,$y) # 107.120 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [June 28, 2023, 7:57am UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/39 "2023-06-28T07:57:18Z")

</div>

Why for case 2 using mapreduce (i.e. `z += mapreduce(*, norm, x,y) `) still allocates ? In the doc it is explicitly said that it skip the intermediate array:

```julia
    mapreduce(f, op, A::AbstractArray...; dims=:, [init])

Evaluates to the same as `reduce(op, map(f, A...); dims=dims, init=init)`, but is generally faster because the intermediate array is avoided.

```

---

<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:** [June 28, 2023, 12:13pm UTC](https://discourse.julialang.org/t/common-allocation-mistakes/66127/40 "2023-06-28T12:13:20Z")

</div>

I think you have a tricky case there. You are first multiplying the elements of `x` and `y`, which would in principle create an intermediate array `z .= x .* y` and then computing the norm of `z`.

Computing the norm of an array can be done in-place, but I doubt that the compiler can handle that automatically for an array that is constructed lazily.

But, to be sincere, I don´t completely understand what `mapreduce` is doing there (I think the docs are not clear on what it does when more than one collection is provided). For instance, if that call to `mapreduce` makes sense, I would think that these two would give the same result:

```julia
julia> x = rand(10); y = rand(10);

julia> mapreduce(*, norm, x, y)
0.015890825295371242

julia> norm(xi*yi for (xi,yi) in zip(x,y))
1.0128277332826312

```

Or, if (that’s what I understand from the docs), the function `f` should be applied to each element to the collections, in which case I think that should error, as `*(x)` is not a defined operation. But that works even with a single collection, so I’m lost here:

```julia
julia> mapreduce(*, norm, [1,2])
1.0

```

[Previous page](https://discourse.julialang.org/t/common-allocation-mistakes/66127.md?page=1)

[Next page](https://discourse.julialang.org/t/common-allocation-mistakes/66127.md?page=3)
