# Memory allocation inconsistency (again...)

**URL:** <https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538>\
**Category:** General Usage\
**Created:** [July 12, 2021, 10:09pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538 "2021-07-12T22:09:40Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [July 12, 2021, 10:09pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/1 "2021-07-12T22:09:40Z")

</div>

When I run the following

```julia
struct Test
     x :: Array{Float64, 1}
     y :: Array{Float64, 1}
end

function test()
   var = Test([1, 2], [1, 2])
    @time @. var.x = var.y - var.x/var.y^2
    @time @. var.x = var.y - var.x/(var.y*var.y)
    return nothing
end

test()

```

I get

```julia
  0.000001 seconds (2 allocations: 16 bytes)
  0.000000 seconds

```

What’s the difference? Why do I get memory allocation when using `var.y^2` (first calculation) but not with `(var.y*var.y)` (second calculation)? I’m using Julia 1.6.1, and I think I was not getting this difference in behavior in previous Julia versions (may be 1.5) (although the present code seems pretty useless, I’m actually getting something similar in an important piece of code, and I’m getting annoyed because I don’t understand what’s happening).

Please help.

---

<div class="post-metadata">

**Author:** ![gbaraldi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gbaraldi/32/22101_2.png) [@gbaraldi](https://discourse.julialang.org/u/gbaraldi)\
**Post date:** [July 12, 2021, 11:20pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/2 "2021-07-12T23:20:57Z")

</div>

Not sure if this helps but it might be weirder

```julia
ulia> function test2()
          var = Test([1, 2], [1, 2])
           @time @. var.x =- var.x/var.y^2 + var.y
           @time @. var.x = var.y - var.x/(var.y*var.y)
           return nothing
       end
test2 (generic function with 1 method)

julia> test2()
  0.000000 seconds
  0.000000 seconds

```

Changing the order removes the allocation

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [July 13, 2021, 10:20am UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/3 "2021-07-13T10:20:28Z")

</div>

It just confirms the oddity. I’ve tried in version 1.7.0-beta3 and the result is the same. However, in version 1.5.3, I get no memory allocations.

```julia
julia> 

  0.000000 seconds
  0.000000 seconds

```

I think this is a bug, something related to the broadcasting function or the dot macro introduced in the 1.6-version update… It’s a pity because this kind of behavior makes the language feel unreliable. ☹

---

<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:** [July 13, 2021, 10:59am UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/4 "2021-07-13T10:59:35Z")

</div>

These are most certainly benchmarking artifacts. I would suggest putting each broadcasting in a different function, returning a meaningful result, and using `@btime`.

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [July 13, 2021, 11:42am UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/5 "2021-07-13T11:42:03Z")

</div>

No, this is definitely some issue with broadcasting. Since 1.5 was not affected, I would recommend git bisect to find the culprit.

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [July 13, 2021, 11:48am UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/6 "2021-07-13T11:48:31Z")

</div>

The allocation is caused by the `RefValue` in the lower code.  
I use Julia 1.6.1.  
You can try the following code.

```julia
struct Test
    x :: Array{Float64, 1}
    y :: Array{Float64, 1}
end

function test1(var)
    @. var.x = var.y - var.x/var.y^2
    return nothing
 end
function test2(var)
    @. var.x = var.y - var.x/(var.y*var.y)
    return nothing
end

var = Test([1, 2], [1, 2])
# Run following code twice to exclude the allocation of compiling.
@allocated test1(var)
@allocated test2(var)

```

`test1` allocates 16 bytes and `test2` doesn’t allocate.  
Check the lower code:

```julia
@code_typed test1(var)

```

```julia
│ %240 = Base.getfield(%239, 1, false)::Base.RefValue{typeof(^)}
│ Base.getfield(%240, :x)::typeof(^)
│ %242 = Core.getfield(%239, 2)::Base.Broadcast.Extruded{Vector{Float64}, Tuple{Bool}, Tuple{Int64}}
│ %243 = Core.getfield(%239, 3)::Base.RefValue{Val{2}}

```

You can see the `RefValue` here, it causes exactly two allocations, each 8 bytes, while:

```julia
@code_typed test2(var)

```

has no `RefValue`. And it only creates immutable values.  
So I wonder what happens here?  
Edit: LLVM IR of `test1` has two additional `jl_gc_pool_alloc` while `test2` has no (except on the error branch, but in this case we don’t throw errors).

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [July 13, 2021, 11:58am UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/7 "2021-07-13T11:58:26Z")

</div>

I am just a Julia user and like the way Julia handles broadcasting. I’ve posted an issue in [https://github.com/JuliaLang/julia/issues/](https://github.com/JuliaLang/julia/issues/). I hope this issue is solved. In the meantime I went back to 1.5.3…

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [July 13, 2021, 12:05pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/9 "2021-07-13T12:05:29Z")

</div>

Some even more interesting observations:  
If I expand the `@.` manually, then the allocation is gone:

```julia
function test3(var)
    copyto!(var.x,Broadcasted(-,(var.y,Broadcasted(/,(var.x,Broadcasted(^,(var.y,2)))))))
    return nothing
end

```

`@allocated test3(var)` is zero…  
Edit: the above lowering code is not exactly correct. See the following post to get the correct lowering.

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [July 13, 2021, 12:24pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/10 "2021-07-13T12:24:49Z")

</div>

So, the problem must be with the macro.

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [July 13, 2021, 12:28pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/11 "2021-07-13T12:28:02Z")

</div>

Noop, I mistake the lower form of the code. It actually should be:

```julia
Meta.@lower var.x .= var.y .- var.x./var.y.^2

```

```julia
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─ %1 = Base.getproperty(var, :x)
│ %2 = Base.getproperty(var, :y)
│ %3 = Base.getproperty(var, :x)
│ %4 = Base.getproperty(var, :y)
│ %5 = Core.apply_type(Base.Val, 2)
│ %6 = (%5)()
│ %7 = Base.broadcasted(Base.literal_pow, ^, %4, %6)
│ %8 = Base.broadcasted(/, %3, %7)
│ %9 = Base.broadcasted(-, %2, %8)
│ %10 = Base.materialize!(%1, %9)
└── return %10
))))

```

copy the lower code you get:

```julia
function test3(var)
    v7 = Base.Broadcast.broadcasted(Base.literal_pow,^,var.y,Base.Val(2))
    v8 = Base.Broadcast.broadcasted(/,var.x,v7)
    v9 = Base.Broadcast.broadcasted(-,var.y,v8)
    Base.Broadcast.materialize!(var.x,v9)
    return nothing
 end

```

It still allocates 16 bytes…

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [July 13, 2021, 1:07pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/12 "2021-07-13T13:07:05Z")

</div>

Ok, I guess I found the reason. It’s because there is an uninlined function call `preprocess_args`.  
Redefine the function fix the bug:

```julia
import Base.Broadcast.preprocess_args
import Base.Broadcast.preprocess
@inline preprocess_args(dest, args::Tuple) = (Base.Broadcast.preprocess(dest, args[1]), Base.Broadcast.preprocess_args(dest, Base.tail(args))...)
@inline preprocess_args(dest, args::Tuple{Any}) = (Base.Broadcast.preprocess(dest, args[1]),)
@inline preprocess_args(dest, args::Tuple{}) = ()

```

@aaraujo71 Can you try the following code?  
On my computer with Julia 1.6.1:

```julia
struct Test
    x :: Array{Float64, 1}
    y :: Array{Float64, 1}
end

function test1(var)
    @. var.x = var.y - var.x/var.y^2
    return nothing
end

var = Test([1, 2], [1, 2])
#compile
@allocated test1(var)
@assert var.x == [0,1.5]

var = Test([1, 2], [1, 2])
@allocated test1(var)
@assert var.x == [0,1.5]

import Base.Broadcast.preprocess_args
import Base.Broadcast.preprocess
@inline preprocess_args(dest, args::Tuple) = (Base.Broadcast.preprocess(dest, args[1]), Base.Broadcast.preprocess_args(dest, Base.tail(args))...)
@inline preprocess_args(dest, args::Tuple{Any}) = (Base.Broadcast.preprocess(dest, args[1]),)
@inline preprocess_args(dest, args::Tuple{}) = ()
var = Test([1, 2], [1, 2])
#compile
@allocated test1(var)
@assert var.x == [0,1.5]

var = Test([1, 2], [1, 2])
@allocated test1(var)
@assert var.x == [0,1.5]

```

You should have 4 allocation number, the first and the third one is a large number including compilation time and the second and the fourth one is 16 (with uninlined function) and 0 (after fix).

---

<div class="post-metadata">

**Author:** ![gbaraldi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gbaraldi/32/22101_2.png) [@gbaraldi](https://discourse.julialang.org/u/gbaraldi)\
**Post date:** [July 13, 2021, 2:23pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/13 "2021-07-13T14:23:56Z")

</div>

Github issue for those wanting to follow it [https://github.com/JuliaLang/julia/issues/41565](https://github.com/JuliaLang/julia/issues/41565)

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [July 13, 2021, 2:26pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/14 "2021-07-13T14:26:06Z")

</div>

I am using 1.5.3 now. However, when I run your code I get nothing. I must be doing something wrong.

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [July 13, 2021, 2:29pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/15 "2021-07-13T14:29:04Z")

</div>

My mistake… You need to add a `println` to each `@allocoated`. I use a REPL so `println` is not needed. The code would be:

```julia
struct Test
    x :: Array{Float64, 1}
    y :: Array{Float64, 1}
end

function test1(var)
    @. var.x = var.y - var.x/var.y^2
    return nothing
end

# compile
var = Test([1, 2], [1, 2])
println(@allocated test1(var))
@assert var.x == [0,1.5]

# before fix
var = Test([1, 2], [1, 2])
println(@allocated test1(var))
@assert var.x == [0,1.5]

import Base.Broadcast.preprocess_args
import Base.Broadcast.preprocess
@inline preprocess_args(dest, args::Tuple) = (Base.Broadcast.preprocess(dest, args[1]), Base.Broadcast.preprocess_args(dest, Base.tail(args))...)
@inline preprocess_args(dest, args::Tuple{Any}) = (Base.Broadcast.preprocess(dest, args[1]),)
@inline preprocess_args(dest, args::Tuple{}) = ()

# compile
var = Test([1, 2], [1, 2])
println(@allocated test1(var))
@assert var.x == [0,1.5]

# after fix
var = Test([1, 2], [1, 2])
println(@allocated test1(var))
@assert var.x == [0,1.5]

```

Simply save the code in the file and run it with Julia. You should get:

```julia
$ julia alloc.jl 
23433466
16
10964697
0

```

@aaraujo71

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [July 13, 2021, 3:02pm UTC](https://discourse.julialang.org/t/memory-allocation-inconsistency-again/64538/16 "2021-07-13T15:02:25Z")

</div>

I get the following:

* * *

```julia
23345722
16
10964665
0

```

(version **1.6.1** , first run)

* * *

```julia
1057944 
0
10964057
0

```

(version 1.6.1, second run)

* * *

```julia
20864725
0
9192799
0

```

(version **1.5.3** , first run)

* * *

```julia
1108545 
0
9192191
0

```

(version 1.5.3, second run)

* * *
