Why does broadcast operation allocate?

Why does this broadcasting allocate?

julia> a = rand(241); b = rand(241);

julia> @time a .-= b;
  0.111315 seconds (188.85 k allocations: 11.037 MiB, 99.59% compilation time)

julia> @time a .-= b;
  0.000016 seconds (2 allocations: 64 bytes)

I know it’s only 64 bytes, but in my actual code, the broadcast is inside a loop… For comparison, if I do the same operation using a loop there is no allocation at all

julia> a = rand(241); b = rand(241);

julia> function minuseq!(a,b)
       for i in eachindex(a)
       a[i] -= b[i]
       end
       end
minuseq! (generic function with 1 method)

julia> @time minuseq!(a,b);
  0.016635 seconds (4.13 k allocations: 229.832 KiB, 99.81% compilation time)

julia> @time minuseq!(a,b);
  0.000005 seconds

It doesn’t:

julia> a = rand(241); b = rand(241);

julia> function minuseq!(a,b)
           a .-= b
           nothing
       end
minuseq! (generic function with 1 method)

julia> @time minuseq!(a,b)
  0.046553 seconds (196.53 k allocations: 11.362 MiB, 99.96% compilation time)

julia> @time minuseq!(a,b)
  0.000003 seconds
1 Like

The allocations come from using non-constant globals when a .-= b is evaluated in the global scope.

When you benchmark a function, there is no need for allocation since everything is type-stable.

3 Likes

Thanks @pfitzseb. I know to be more careful testing things in the REPL now. Now need to find an actual MWE for the allocations during broadcasting in my code…