Navigation:  Programming Cookbook > Weak References and Finalization >

And finally??

Previous pageReturn to chapter overviewNext page

Generally we don't want to be bothered about the expiry of an object, we let the VM deal with cleaning up all the old rubbish. Finalization is for those cases where we do want, or need, to get involved.

Dolphin provides a mechanism by which objects are informed when they are about to expire. How objects respond to this notification, i.e. how they finalize themselves, is their own business - Zen and the Art of Finalization provides advice.

Any Dolphin object can be marked as requiring finalization, on an instance specific basic, and is then guaranteed to receive a #finalize message before it actually dies (i.e. the memory it occupies is freed). The default implementation of #finalize (in Object) is to do nothing:


  "Perform any death-bed operations as the receiver is about to expire. The default

  is to do nothing.

  It is not necessary to remove an objects finalization mark, since this has already been

  done by the garbage collector. Should you wish an object to be finalized again, you

   must send it #beFinalizable again (this can be done from the #finalize message, but

   be careful as this may leave the object in an endless loop of finalizations, consuming

   system resources).

  The receiver will cease to exist at some time after its finalize method has completed (at

  the very latest at the next GC), unless that method causes additional references to be

  taken to the receiver. It is a good idea to remove any circular references in an object's

  finalize method to shorten its remaining life.

  Note that this method is only sent to objects which are marked as requiring

  finalization (see #beFinalizable) when their last strong reference is removed. The

  object will not receiver the message immediately, but only on the next run of the

  Finalizer process (which runs at a low priority), and if the object has outstanding

  weak references, only then after a run of the full garbage collector (which is

   necessarily a relatively infrequent occurrence)."


The comment in this method is quite instructive, but we'll ignore some of the details for now.

The Finalization pattern explains the procedure for implementing finalization in some detail, but in summary:

Send the object the #beFinalizable message at some time during its life (probably immediately after acquiring some external resource).
Implement the #finalize message to perform the necessary clean up.
Should you wish to revoke an objects right to finalization, then send it the #beUnfinalizable message.

Having taken these steps you can merrily create objects in the certain knowledge that they will clean up after themselves when they are no longer required, because the MemoryManager makes certain guarantees to objects marked as requiring finalization (those it considers to have "last requests"):

Such objects will receive a #finalize message, at some "interval" after their last reference from an object not marked as weak has been cleared (weak references have no effect on the lifetime of an object). The "interval" in question is of unspecified duration, but would normally be after the next garbage collection cycle (GC).
Objects with last requests are guaranteed to receive only a single #finalize message, no matter how many objects weakly reference them.
Objects with last requests will die immediately after they have carried out their last requests, but
Objects can be rescued in their finalize message simply by taking a further reference to themselves i.e. by assignment into some non-temporary variable. Such rescued objects will not receiver a further #finalize message, unless they are sent #beFinalizable again.

The memory manager is careful to ensure that objects queued for finalization remain valid until their finalization is complete (and of course objects can rescue themselves in the #finalize method too, although they will have lost all their former weak references), and this can result in some apparent strangeness when finalizable objects reference other finalizable objects. The precise finalization behaviour is defined in The Rules. It may be important to understand these rules in order to correctly code #finalize methods where non-trivial relationships exist between finalizable objects and/or weakly referencing objects, but this is an advanced topic so be warned!.

It is worth noting that finalization is performed asynchronously by a lower priority process, and this has a number of implications:

Finalization runs at a low priority so that it does not disrupt or delay normal processing.
Finalization may itself be considerably delayed (perhaps indefinitely), and this may significantly extend the life of objects which would otherwise be garbage collectable.
Process synchronisation is not normally necessary because, by definition, an object referenced from another process has no legitimate reason to be lurking in the finalization queue (it has references!). If, however, clean-up operations reference objects which may be in use by other processes, then process synchronization may be required.