It is currently possible to create (*glib.Object).Connect closures which close over gotk3 objects, or include them as part of the userdata. This results in the glib package creating a closure context with (reflected) references to the object and saving it globally in a map of GClosures to closure contexts.
Closure contexts are never removed from glib's global map until the GLib runtime frees (when ref count drops to 0) the object the closure is connected to and finalizes the closure. However, these closure contexts still hold references to gotk3 objects, and because they are still technically accessable through the glib closure context map, the Go garbage collecter is unable to know that the objects are no longer live. This results in the gotk3 object, the Go closure, the closure context, and the GClosure never being freed.
The following code snippet demonstrates the problem:
{
b, err := gtk.ButtonNew()
if err != nil {
// badness
}
runtime.SetFinalizer(b, func(_ *gtk.Button) {
fmt.Println("finalizing button")
})
b.Connect("clicked", func() {
_ = b // This introduces the circular reference
})
} // b is out of scope, and was never added to another container
runtime.GC() // b's finalizer does not run
It is currently possible to create (*glib.Object).Connect closures which close over gotk3 objects, or include them as part of the userdata. This results in the glib package creating a closure context with (reflected) references to the object and saving it globally in a map of GClosures to closure contexts.
Closure contexts are never removed from glib's global map until the GLib runtime frees (when ref count drops to 0) the object the closure is connected to and finalizes the closure. However, these closure contexts still hold references to gotk3 objects, and because they are still technically accessable through the glib closure context map, the Go garbage collecter is unable to know that the objects are no longer live. This results in the gotk3 object, the Go closure, the closure context, and the GClosure never being freed.
The following code snippet demonstrates the problem: