Garbage Collection catch-22 with blocks - Further complications

Peter Smet peter.smet at flinders.edu.au
Mon Jul 5 10:44:55 UTC 1999


To put this problem in context, let me put forward some of the issues I am
coming across with garbage collection and a Central Event dispatching
mechanism. The publishers, and subscribers are both held in Weak Key
Dictionaries. Initially, I held strong references to the messages and
arguments that needed to be dispatched to the subscribers. After thinking it
through (and checking the gc), I realised that this wasn't going to work. If
the arguments of any message refer back to a publisher or a subscriber, you
get a circular reference that effectively prevents the gc from ever
collecting these objects. This turns out to be a very common situation. It
is virtually impossible to prevent these situations from arising, since the
argument could be a complex compound structure that indirectly refers back
to a publisher or subscriber held in a WeakKeyDictionary.

My answer to this is to hold empty (nil) argument arrays in all messages to
subscribers, and merely "pass on" the arguments from a #trigger: anEvent
with: anArgument to the appropriate subscribers. Since the mechanism now
holds no strong references to arguments, the publishers and subscribers will
be garbage collected appropriately.

This means that #trigger: anEvent must pass along the arguments that any
subscribers may require. This causes a problem in that some subscribers
responding to a single event might have selectors that require different
numbers of arguments. I have worked around this by letting anEvent be
triggered with n arguments, but the event dispatcher strips out any excess
arguments not required by particular subscribers.

This seems a good compromise. It means that you can't trigger events with n
arguments that send selectors with n + 1 arguments. This is a limitation,
but in practice most #triggers: pass along the correct number of arguments
anyway.

Blocks are more complex. You need to provide a strong reference to the block
or it will disappear. As discussed already, this gets kind of ugly, since
the block may also refer to a publisher or a subscriber (via its receiver
variable). If this is the case, once again the garbage collector can't be
guaranteed to work. Some possible solutions are:
1. Make the publisher hold onto the block via an instance variable. This
solves the gc collection problem, but means that only subclasses of Model
can use the #when: do: construct. Effective but disappointing.
2. Make the receiver variable in the block a weak reference. This works with
regard to garbage collection, but it is hard to guarantee that blocks will
execute correctly. For example, if there are lots of strong references to
the block, but no references to the receiver. This means a block can be
invoked after losing the information it requires to execute. Unpredictable.

If there are other approaches I would like to hear them. To me approach 1 is
probably the best, since it is both simpler and safer. This approach is also
uniform in that when: anEvent do:  aBlock can be translated to:
when: anEvent send: #value to: aBlock (including its value: variants).
Since the block now becomes the subscriber, like any subscriber, it will
disappear if there are no strong references to it.

Anyway, I will post the latest version (with dubious block support) onto the
wiki page. Feel free to hack it.

Peter





More information about the Squeak-dev mailing list