Navigation:  Programming Cookbook > Weak References and Finalization >

Weak References

Previous pageReturn to chapter overviewNext page

A Weak Reference (also called a Weak Pointer Reference) is one whose hold on other objects is only tenuous, and which will permit those objects to be garbage collected if there are no references to them from the more assertive members of the object community.

The fundamental concept behind weak references is simple; they are ignored by the garbage collector when it is traversing the object reference graph from the roots of the world in an attempt to locate accessible objects, and consequently objects which are reachable from the root only if a weak link is followed, are garbage.

Dolphin permits any indexable pointer object to be weak - the attribute is not limited to objects of a particular class as in some other Smalltalks. The named instance variables of such weaklings are not weak - if they were they would find it well nigh impossible to maintain their internal state (they'd risk losing it on every GC). This is not, in practice, a limitation because it is always possible to simulate a named variable with a pair of accessors and a fixed index, and in any case it is mostly collections which need to be weak, and these are more conveniently implemented with indexable variables.

The memory manager also makes certain guarantees to objects marked with the weak attribute:

If they belong to a mourning class (i.e. one with the Mourning behaviour bit), they will receive one, and only one, #finalizeElements: message following each GC should they suffer a bereavement or bereavements, and the argument will inform them how many new corpses they have (if they've not been tidy, they may still have others too). Weaklings which are not members of mourning classes receive no notification of losses.
Weak references to objects which expired (or were queued for finalization) during a GC cycle, will have been replaced with references to the corpse object.
Weak references will only be replaced with corpses if the formerly referenced object has no remaining strong references. It is not guaranteed, however, that the object will actually expire, because if it is marked as finalizable, it is within its rights to rescue itself in its #finalize method. Any former weak references will not be reinstated if it rescues itself.
A mourning weakling will receive an #elementsExpired: message in respect of imminent deaths before those dying objects have had a chance to complete their last requests (if they have any).

Note that the GC does not remove references to corpse from previous reapings. Should this be the behaviour desired, then weaklings must tidy away corpses themselves in their #elementsExpired: method (e.g. see WeakArray>>nilAllCorpsesAndDo:).

You may be wondering why the memory manager doesn't just nil expired weak references during the GC, rather than replacing them with corpses? Well, this might work for simple data structures, but many objects (e.g. hashed collections) are too complicated, and need to be able to identify which of their elements have been lost in order to carry out efficient and effective repairs. One might also need to be able to identify the deaths in order to perform pseudo-finalization on behalf of objects which are not in themselves finalizable (e.g. by keeping a parallel collection of "executors").

How does one implement weaklings? This depends on whether the weaklings need go through a mourning process in order to repair themselves after suffering bereavements (i.e. they need to implement #elementsExpired:). There are no special requirements on bereavement immune weaklings which do not need mourn, but otherwise the procedure is quite involved, not least because mourning weaklings need to be process safe. It is preferable to re-use an existing weak collection (directly or by encapsulation) rather than implementing your own. If this is not possible, then the Weak Collection pattern explains the procedure in detail.

Example weaklings can be found in Dolphin implementing the symbol table, and the dependency and event mechanisms.