How to force an object to be freed by the garbage collector

From this very old post (https://groups.google.com/g/julia-users/c/QkChqeKnd9g/m/cqltIs5doQoJ) I was led to believe that the call to gc below would free the memory allocated by X, but it doesn’t.

How could I force the release of the memory allocated by X here?

(dimensions chosen to bomb if the memory allocated by X does not get freed)

function testme()
    X = rand( 14_000_000_000 )
    Y = sum( X )
    X = nothing
    GC.gc()             # why does the memory not get freed here?        
    Z = rand( 14_000_000_000 )
    Y += sum( Z )
    return Y
end

function tester()
    Y = testme()
    return Y
end

println( tester() )
1 Like

Warning, don’t try this on a Windows 64 GB system: your swap will start spinning…

Yes, replace 14 with 7 on a 64Gb system

Now that I rebooted my system again: we should look for a better way to analyze this.

The following seems to release memory for the GC.gc() call at the toplevel

function testme()
    X = rand( 2_000_000_000 )
    Y = sum( X )
    X = nothing
    GC.gc()             # why does the memory not get freed here?        
    Z = rand( 2_000_000_000 )
    Y += sum( Z )
    return Y
end

function tester()
    Y = testme()
    return Y
end

println( tester() )
GC.gc()

as visible in Task Manager. So is it a scope problem?

1 Like

Sorry.

Yes, there are a number of changes that one could make that would make the memory get released, but I would like to understand more fundamentally what would work, what wouldn’t, and why.

(Other examples include sticking @sync in front of GC.gc() and calling garbage collection in the calling function)

No need to apologize. I willfully ignored the warnings…

1 Like

This code should work:

function testeme()
       Y = (() -> begin
           X = rand(1_000_000_000)
           sum(X)
       end)()
       GC.gc()
       return Y
       end
2 Likes

as a side note: is there a difference between this and a let-block?

Y = let X = rand(1_000_000_000)
    sum(X)
end
2 Likes

Thanks @Ronis_BR . Unfortunately, in my actual program there are a lot of other objects that would be defined within your inner scope that I would want to survive. Returning all that stuff is ugly.

There is a difference since with the let block the memory isn’t released. I don’t know why.

1 Like

As a follow-up, why would

@sync GC.gc()

release the memory even absent @Ronis_BR 's construction?

Looking at the result of @code_typed testme(), it doesn’t appear that X = nothing actually does anything. It seems that it is removed by the optimizer because (aside from GC) it has no observable effect.

@aviatesk is this something that EA could help with? Or is this more an issue of optimization not recognizing (intentionally or accidentally) that X = nothing has an effect w.r.t GC?

4 Likes

Did anything come out of your inquiry?