Navigation:  Appendix B: Dolphin Pattern Book > Object Lifetime Patterns >

Object Liberation Strategy

Previous pageReturn to chapter overviewNext page

Context

Some objects represent external resources. How can we ensure that these external resources are correctly reclaimed when the object is garbage collected.

Solution

By convention, Dolphin adopts a number of methods associated with the termination of objects:

#basicFree

#free

#finalize

#release

#basicFree

The #basicFree method should free (de-allocate) external resources owned by the receiver. After this has occurred the receiver is left in an invalid state and, as such, it is assumed that #basicFree can only be called once. So #basicFree:

frees external resources
may leave the receiver in an invalid state
can only be called once

#free

The #free method should free external resources (typically by sending #basicFree) and also nil the instance variables referencing those external resources. This will allow these objects to recreate their valid state (often using Lazy Initialization) from the information contained in the receiver. Because the appropriate instance variables are nilled, #free can be sent to an object more than once. So #free:

generally calls #basicFree
nils resource variables
allows the receiver to recreate its valid state (often lazily)
can be called more than once

#finalize

Finalizable objects receive the #finalize message (only once) just before certain death. Objects can be marked as finalizable by sending them the #beFinalizable message. #finalize should generally call #basicFree since there is no need to call #free as the object is about to die anyway. Therefore #finalize:

is received just before certain death
generally sends #basicFree
should only be sent by the finalization mechanism
is only sent once

#release

The intention of #release is that it should remove circular references and dependents from the receiver. This was a convention adopted by the early Smalltalk-80 systems where weak references were not available. Since it is not necessary to remove circular references which involve a weak reference, the introduction of Weak Collections has meant that #release is less useful in modern Smalltalk programming. So #release:

removes circular references and dependents
is generally not that useful now that weak references are available

Known Uses

GraphicsTool is an abstract class which defines behaviour common to GDI objects (pens, brushes etc).

GraphicsTool uses Lazy Initialization to create the external resource, and Object Liberation Strategy to free it.

GraphicsTool>>handle

  "Answer the receiver's handle. If unrealized then attempt to realize it first."

  handle isNil

      ifTrue: [self realize].

  ^handle

 

GraphicsTool>>realize

  "Realize (create) the external resource associated with the receiver,

  but only if not already realized. Subclasses must implement #basicRealize"

  ^self isRealized

      ifFalse: [

          self

              basicRealize;

              beFinalizable]

 

GraphicsTool>>basicRealize

  "Private - Realize (create) the external resource associated with the receiver, sent

  from the public method, #realize, if not already realized."

  ^self subclassResponsibility

 

GraphicsTool>>free

  "Free external resources held by the receiver, and leave in a state such

  that the receiver will be re-realized the next time it is accessed."

  (self isRealized and: [self ownsHandle]) ifTrue: [

      self beUnfinalizable.

      self basicFree.

      handle := nil]

 

GraphicsTool>>basicFree

  "Private - Free up external resources held by the receiver."

  GDILibrary default deleteObject: handle

 

finalize

  "Private - The receiver is about to expire, so free any external resources. We use #free

  rather than #basicFree just in case the receiver has been explicitly freed whilst it was

  waiting in the finalize queue."

  self free

 

Brush is the GraphicsTool subclass which represents Win32 GDI brushes:

Brush>>basicRealize

  "Private - Create the external brush resource associated with the receiver."

  self ownsHandle

      ifTrue: [self ownedHandle: self createHandle]

 

Brush>>createHandle

  "Private - Answer an external handle to a new brush as described by the logbrush structure."

  ^GDILibrary default createBrushIndirect: logbrush

 

Related Patterns

Weak Collections, Finalization