When does the garbage collector runs?

Hello everyone,

I was hoping that GC would free some memory, and I noticed that it does not works when I’m using @btime. Here, a basic example

using BenchmarkTools

function a(N)
	x = rand(N)
	@time y = sin.(x)
	x = 1; y = 1;
	GC.gc()
end

function b(N)
	x = rand(N)
	@btime y = sin.($x)
	x = 1; y = 1;
	GC.gc()
end

a(10^8)
GC.gc() # actually clears the memory

b(10^8)
GC.gc() # does not clears the memory

There are two points that I would like to understand.

  • I can see in my System Monitor that memory is available only when I run GC on the REPL, so, why does the GC.gc() does not free memory inside my a or b function ? In this a feature of GC ?

  • I need to exit Julia to get memory after using my b function. What does the @btime has in special that does not allow the GC to work ?

For reference, I’m using Julia v 1.0 on Ubuntu

Inside a function, it’s possible there is still a reference to an object (on the stack) that prevents the GC from freeing it. When these references get overwritten depends on what the compiler decides to do. It could make sense for us to insert code to clear some references more aggressively, but it still won’t necessarily be predictable.

I’m not sure what the issue with @btime might be. However, in its expansion I notice it leaves a bunch of global variables around, so it might be retaining references that way. It’s possible the macro needs to be fixed to make those local.

I tired to look a bit into it (https://github.com/JuliaCI/BenchmarkTools.jl/pull/117) but I think that for each @btime call a new function is generated with x interpolated into the function body, thus keeping it alive.

1 Like