conformal / gotk3

Go bindings for GTK3
ISC License
471 stars 84 forks source link

Connect closure memory leaks #55

Open jrick opened 10 years ago

jrick commented 10 years ago

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