Reduce memory allocation in copying array

Hello everyone.

I was wondering if there is a way to reduce the memory allocation of a code like this:

julia> function funza(N)
         a = Array{Float64}(undef,5)
         b = Array{Float64}(undef,5)
             for i=1:N
             b = rand(5)
             a = b
             # println(a)
             # println(b)
             end
         end
funza (generic function with 1 method)

Which gives:

julia> @time funza(10^6)
  0.146703 seconds (1.00 M allocations: 122.071 MiB, 15.50% gc time)

There is essentially an allocation every time the row:

b = rand(5)

is executed.

Even if I don’t really think it’s possible, is there any way to reduce the memory allocation of such a code?

Thanks a lot to everyone.

this allocates rand(5) then bind b to it. Do this instead:


julia> using Random

julia> @benchmark (Random.rand!(b)) setup=(b=zeros(5))
BenchmarkTools.Trial: 10000 samples with 996 evaluations.
 Range (min … max):  23.196 ns … 502.040 ns  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     24.087 ns               ┊ GC (median):    0.00%
 Time  (mean ± σ):   24.902 ns ±   5.406 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

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

 Memory estimate: 0 bytes, allocs estimate: 0.

It’s not easy to say exactly how much you can reduce allocations. Your function doesn’t return anything, so it can be replaced with

function funza(N)
    return nothing
end

which has zero allocations. What should the function return? If you can say that, then it’s possible to make recommendations.

I’ll try to interpret your code. Perhaps you want the function to print some random numbers? Then you can do

function funza(N)
     b = Array{Float64}(undef,5)
     for i in 1:N
         b .= rand.()  # this updates b in-place, and does not allocate anything
         a = b  # this does not allocate, it just puts the label a on the same vector as b
         println(a)
         println(b)
     end
end

Now, println itself is going to create most of the allocations, there will only be a single allocation of a Float64 vector.

ah yes…always forget about dot fusion… too magical

You can also do:

using Random

function funza(N)
    a = Array{Float64}(undef,5)
    b = Array{Float64}(undef,5)
    for i=1:N
        rand!(b)
        a .= b
        # println(a)
        # println(b)
    end
end

julia> @time funza(1e6)
  0.022101 seconds (2 allocations: 256 bytes)

Thanks to all of you who responded. Your answers have all been great, but it’s my fault: I posted too simple code that doesn’t reflect what I’m trying to do (posting the real code here would be far too complex).

I will close the topic, and maybe I will open another one in the future in case of need.

Thanks again to everyone and have a nice day!