[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
--
http://apfelmus.nfshost.com
More information about the Haskell-Cafe
mailing list