Memory allocated when using a `struct`as function argument?

I am relatively new to Julia. I am trying to write code that avoids unnecessary memory allocation, but I do not completely understand when memory allocation happens. Here is an example where I can’t figure out what is going on.

using Random

function rantest1(N)
    a=0
    for _=1:N a+=rand() end
    a/N
end

When I run this, I get few allocations:

julia> @time rantest1(10000)
  0.000019 seconds
0.49859463237489143

But if I create a random number generator as below, I get one allocation per call of rand:

struct ran
    RNG::AbstractRNG
end

function rantest2(uf,N)
    a=0
    for _=1:N a+=rand(uf.RNG) end
    a/N
end
julia> rr=ran(MersenneTwister(3))
ran(MersenneTwister(3))

julia> @time rantest2(rr,10000)
  0.000138 seconds (10.00 k allocations: 156.266 KiB)
0.5014996807071508

However, if I pass the RNG object directly instead of through a struct, the allocations do not happen:

function rantest3(rng,N)
    a=0
    for _=1:N a+=rand(rng) end
    a/N
end
julia> @time rantest3(rr.RNG,10000)
  0.000033 seconds (2 allocations: 32 bytes)
0.5055755161896126

I would appreciate if someone can explain, or point to an explanation, of why all these allocations are happening when I use a struct in the argument of the function.

AbstractRNG is an abstract type. If you use

struct ran{T<:AbstractRNG}
    RNG::T
end

it will be fast. (see Performance Tips · The Julia Language)

8 Likes

Thank you @Oscar_Smith. Yes, defining ran that way avoids the allocations.

I had read that part of the docs, but it clearly didn’t really sink in. I’ll try to get to understand abstract types better.

Thanks again.

1 Like