Pattern: Object Liberation Strategy


Context

Some objects represent external resources. It is important that these external resources are released when the associated object is garbage collected.

Solution

There are a number of methods associated with the termination of objects:

#basicFree

The #basicFree method should free (de-allocate) external resources owned by the receiver. The receiver is left in an invalid state and, as such, #basicFree 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. These objects can recreate their valid state (often using Lazy Initialisation) from the information contained in the receiver. Because the appropriate instance variables are nilled, #free can be sent to an object more than once.

#finalize

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

#release

The #release method should remove (from the receiver) circular references and dependents. 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.

Known Uses

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

GraphicsTool uses Lazy Initialisation 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