|
Navigation: Appendix B: Dolphin Pattern Book > Object Lifetime Patterns > Object Liberation Strategy |
![]() ![]()
|
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