GLFW callbacks not released
See original GitHub issueSummary
After closing a GLFW rendering window GLFW ande some referenced objects remain in memory.
Steps to reproduce
- Platform: Desktop
- Framework Version: .NET 5
- API: OpenGL
- Run the code from ‘Tutorial 1.1 - Hello Window’ in the debugger with a breakpoint on the closing brace of Main.
- Once the breakpoint is hit create a memory snapshot and open it.
- Inspecting the snapshot shows that the callbacks created in GlfwWindow (e.g. WindowCloseCallback or FramebufferSizeCallback) are still in memory.
Comments
From some debugging I think this might be due to those callbacks being lambdas/closures referenced by GlfwWindow.
Also I am not sure if GlfwWindow.UnregisterCallbacks acutally unregisters all of them. At least GCUtility.Unpin does not find the corresponding handles. To me it looks like only the most recent one is actually pinned due using PinMode.UntilNextCall.
I could get rid of the objects locally by making two changes:
- In Glfw change all Callbacks from
[PinObject(PinMode.UntilNextCall)]
to[PinObject]
- In GlfwWindow.UnregisterCallbacks after calling Unpin also set the fields to null
Since I do not understand this code well enough I doubt this is the right thing to do. The first step was because I noticed that GCUtilities.Pins contained only a single handle at all which causes Unpin not to find the callbacks in there.
Background
I have a service for rendering 3D scenes to images. This creates a new window for each request and I found that the memory usage keeps growing over time. Doing some memory profiling brought up that those Glfw* objects remain in memory.
Issue Analytics
- State:
- Created 2 years ago
- Comments:14 (14 by maintainers)
Top GitHub Comments
To clarify: I’d prefer the slot to be per native entrypoint rather than per entire method, because what if we had two overloads of the same native function but with different delegate types? We still need to free the other one.
By the way, thanks for the engaging conversation! You seem to have caught onto all this really quickly, and your input is really helpful 😃
The GC slots aren’t actually used anywhere other than the GC Utility to my knowledge, which accepts the integer as an arbitrary index to map to a list of GC handles.
GCUtility.PinUntilNextCall
will resolve all GC handles for the given slot.Right now the slot is always 0. This is the bug, as it’s causing only one delegate to be pinned at any given time (well, it’s one of the bugs, the other is that GCUtility doesn’t do a null check and as a result doesn’t properly deallocate).
We need to define that slot value, and I don’t think it makes sense to give each individual overload of the same native function a slot. So, this presents us with two options:
I could be missing something though!