Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory Leak: GC does not deallocate values allocated while it was turned off, unless specifically requested #45068

Closed
Clemapfel opened this issue Apr 23, 2022 · 7 comments
Assignees
Labels
bug Indicates an unexpected problem or unintended behavior GC Garbage collector

Comments

@Clemapfel
Copy link

Hi, the following is a memory leak:

x = 1234
while (true)
    GC.enable(false)
    x = rand()
    GC.enable(true)
    #GC.collect(GC.GC_AUTO)
end

This slowly fills up the RAM until the OS kills the process. With #GC.collect(GC.GC_AUTO) commented in, this code behaves as expected. Without any of the GC. calls, no memory leak occurs either.

Clearly the GC is still updating the roots, otherwise GC.collect would have no effect. For some reason, the unused rand() values are never deallocated. This same behavior is exhibited if implementing the above using the C-API.

Tested on Julia 1.7.2, on Ubuntu 20.04.2 LTS, 64-bit, but I've asked a few people, and they all reproduced it.

I also opened a discourse thread about this

@oscardssmith oscardssmith added bug Indicates an unexpected problem or unintended behavior GC Garbage collector labels Apr 23, 2022
@oscardssmith
Copy link
Member

I can reproduce this on master.

@oscardssmith
Copy link
Member

I believe what's happening here is that since you disable GC for all the allocations, there are no GC safe points in this code. that said the call to enable GC should introduce a safe point. I'm not sure why it doesn't...

@vtjnash vtjnash closed this as completed Apr 23, 2022
@vtjnash
Copy link
Member

vtjnash commented Apr 23, 2022

If you have any GC.disable calls in your code, the GC may take that as license to not doing GC at all (particularly if all of your code runs with GC disabled as it does in the example)

@oscardssmith
Copy link
Member

that doesn't seem right to me since that would make GC.disable unusable.

@oscardssmith oscardssmith reopened this Apr 23, 2022
@Clemapfel
Copy link
Author

Clemapfel commented Apr 23, 2022

Even if this was true, why would GC.enable not hint to the GC that I would like it to start working again. If the GC may decide to just not do its job after disabling, then GC.disable is pointless and it would introduce a memory leak anytime it is called

If this is indeed intended behavior, then I would consider that a flaw in the design, or, at the very least, there is missing documentation for GC.enable that explains this behavior

@vchuravy
Copy link
Member

Look in the Julia source for calls to maybe_collect those are all the points in the runtime that might cause GC to run. Generally speaking the GC will only check if it is necessary to run before an allocation.

GC.enable/GC.disable are lightweight ways of turning this check on or off, they themselves need not cause the check to occur. So this is very much working as intended.

I believe what's happening here is that since you disable GC for all the allocations, there are no GC safe points in this code.

A safepoint corresponds only to when another thread wants to run GC (and I believe the allocation is still a safepoint)

@Deduction42
Copy link

I was able to reproduce this in a top-level script, but putting it in a function stops this endless memory expansion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior GC Garbage collector
Projects
None yet
Development

No branches or pull requests

6 participants