[Haskell-cafe] threepenny-gui: garbage collection

Heinrich Apfelmus apfelmus at quantentunnel.de
Sat Jan 3 10:34:07 UTC 2015

Tom Ellis wrote:
> Suppose that each time I make a particular threepenny-gui widget, call it a
> `Foo`, I register an event handler using `on` so that the `Foo` can change
> its appearance based on some `Event`.
> Suppose I create, show, and hide a billion `Foo`s, each one never to be
> shown again.  Can they be garbage collected?  Presumably there is something
> storing the callback that was registered for the `Event` and the callback
> refers to the `Foo`.  How then can the `Foo`s be freed?
> `Reactive.Threepenny.register` talks about an "unregister" action but says
> "FIXME: Unregistering event handlers does not work yet.".  But how could it
> be known anyway when to unregister?  Is there not the possibility of a space
> leak regardless?

(Threepenny author here.)

This is a classic example of a circular reference that occurs in every 
GUI program: A widget keeps a reference to an event handler, which in 
turn keeps a reference to the widget.

Of course, GHC's has a well-designed garbage collector that can handle 
this, but in Threepenny, the situation is actually worse: the widget is 
managed by the JavaScript runtime, whereas the event handler is managed 
by the Haskell runtime. I don't know any garbage collector that can 
resolve cross-runtime circular dependencies.

Still, I managed to solve this problem to some extend. :) Essentially, 
Threepenny mirrors dependencies between JavaScript DOM elements on the 
Haskell side, and thus allows the Haskell garbage collector to handle 
this. (I wouldn't want to touch JavaScript garbage collectors with a 
ten-foot pole.) For your concrete situation, this means that as long as 
the `Foo` widgets are not inserted into the DOM tree in the browser, and 
you only use DOM events on them (`UI.click` etc), they will indeed be 
garbage collected properly whenever their lifetime ends in your Haskell 
program. (At least, that's the plan. I have tested that it works, but 
garbage collection is a tricky business, so I wouldn't bet my life on it 
just yet.)

Note that I do have to mirror the JavaScript memory layout, so this only 
works for the `Element` type at the moment. If you use the `ffiExport` 
function to export event handlers to the JavaScript side, then they will 
not be garbage collected.

The `Reactive.Threepenny.register` function is totally separate from 
this, because it doesn't talk to the JavaScript runtime at all. You're 
right that there might be some issues with `unregister`, but I haven't 
thought about this yet.

Best regards,
Heinrich Apfelmus


More information about the Haskell-Cafe mailing list