Object Finalization
- 1. Finalization Overview
- 2. Finalizing when an Object is Garbage Collected
- 3. Finalizing when the Stack Unwinds
- 4. Customizing Finalization
1. Finalization Overview
Objects use resources that must be released when the object is no longer needed. For most objects, the only resource used is the memory they are stored in, which may reference other objects internal or external to Smalltalk. While the garbage collector automatically releases the memory used by internal unreferenced objects, it does not release any associated external resources.
Ambrai Smalltalk objects can manage their external resources through finalization. You have the opportunity to finalize an object when the object is garbage collected and/or when the call stack unwinds.
2. Finalizing when an Object is Garbage Collected
The garbage collector finalizes only registered objects. To register or unregister objects with the garbage collector, use the #beFinalizable or #beUnfinalizable methods. For example:
anObject beFinalizable. anObject beUnfinalizable.
To check whether an object has been registered with the garbage collector:
anObject isFinalizable.
Note that the garbage collector makes no guarantees as to when and in what order objects will be finalized. If you need an object to be finalized immediately, then use an unwind block to finalize the object when the stack unwinds. However, you should still register finalizable objects with the garbage collector in case users of your class do not use an unwind block.
3. Finalizing when the Stack Unwinds
An unwind block can be specified when evaluating an arbitrary block of code. This unwind block always evaluates when the stack unwinds, which happens when:
- the main block executes to the end
- the main block returns from the enclosing method
- the main block invokes a method that returns to an outer scope
- any outer scope handles an exception without resuming
Use the #finally: or #ensure: methods to evaluate a block with an unwind action. Here is a example of a common situation where you want to ensure that a file will be closed after it is opened.
stream := file open. [ "do your reading or writing here" ... ] ensure: [stream close].
The advantage of using an unwind block is that finalization will occur immediately after the object is not needed. The disadvantage is that the object being finalized cannot be shared. For example, the code above assumes the stream is not referenced elsewhere and that it is safe to close it without affecting another object that may be using the stream.
4. Customizing Finalization
To customize finalization for arbitrary objects, you can specify a block of code to be evaluated when the object is finalized.
anObject beFinalizableWithAction: [:object | Transcript nextPutAll: 'finalizing: '; print: object; cr].
Alternatively, to customize finalization for your own objects, implement a #finalize instance method in your class:
MyClass >> finalize resource isNil ifFalse: [ resource release. resource := nil]
Make your object finalizable immediately after you allocate an external resource within any method of your class:
MyClass >> initialize resource := MyResource new. self beFinalizable
To be more efficient, you can add a finalizer instance variable to your class. In addition to the #finalize method, you will need to implement the following two instance methods:
MyClass >> finalizer finalizer isNil ifTrue: [ finalizer := Finalizer finalizee: self]. ^finalizer MyClass >> finalizerOrNil ^finalizer
Last modified May 22, 2006.