parent previous next question (Smalltalk Textbook 48)

WeakReference & Finalization

WeakReference and Finalization may be unfamiliar to most Smalltalkers because they are related to garbage collection. You do not need to know about them to write ordinary Smalltalk programs. But as soon as you have need to communicate with another Smalltalk system or handle external objects such as operating system resources, you'll need to understand them. And at this point in this text, it is good to understand them before proceeding.

Garbage collection is a mechanism to crate free space for new objects by deleting and collecting the memory used by objects which are no longer needed. In Smalltalk you can ignore memory allocation and deallocation because objects which are no longer needed are automatically garbage collected. In C++ you must manage memory space yourself via free, delete, constructors and destructors.

Even though garbage collection is automatic, you may invoke it explicitly. Evaluate the next expression and the mouse icon should change to a trash can for a brief time while garbage is being collected.


Program-48-1: (ObjectMemory; garbageCollect, gc, garbage collection)
------------------------------------------------------------
ObjectMemory garbageCollect
------------------------------------------------------------

This next message prints some information about garbage or free space during garbage collection.


Program-48-2: (ObjectMemory; verboseGlobalCompactingGC, gc, garbage collection)
------------------------------------------------------------
ObjectMemory verboseGlobalCompactingGC
------------------------------------------------------------

There are several ways to invoke garbage collection. Please refer to the 'collecting garbage' category of the 'ObjectMemory' class.

Garbage collection deletes only unused objects; never necessary objects. Necessary objects are those linked by a 'StrongReference' from system roots like a global dictionary or context. 'StrongReference' is an object pointer (aka OOP) which is like an address for an object in the memory space. If you create an object (instance of a class) then store it in another object (e.g. OrderedCollection), an OOP is stored rather than the object.

Another type of OOP is called a 'WeakReference'. I would like to describe it presently, but it is difficult to describe without preparation. So, first of all let me give you a metaphor as an introduction to 'WeakReference' and 'Finalization' (commonly associated with 'WeakReference').

Suppose the president of a company has a son-in-law. Suppose also that he gives this person a job, even though the son-in-law is incompetent. Nobody can get rid of the son-in-law because he is related to the president (WeakReference). Now suppose the president makes a few bad decisions at a time when business is down. The board of directors will fire the president and reorganize (Finalization) the company. Now the incompetent son-in-law no longer has connections (WeakReference) and he is let go.

'WeakReference' and 'Finalization' behave like this story. Let's say object X has a 'StrongReference' to object A and a 'WeakReference' to object B. Then if object A is somehow deleted for 'Finalization', object X, which only has a 'WeakReference' to object B, will also be deleted. A 'WeakReference' is not enough to keep object X around.

Here is another example. Suppose there is a collection and objects A, B and C. C stores the collection. B is an element of the collection. And B is also referred to by A. The situation is :

-----------------------------------------------------------
C             --StrongReference -->  a collection
a collection  --WeakReference   -->  B
A             --StrongReference -->  B
-----------------------------------------------------------

If A unlinks its 'StrongReference' to B for any reason, then B is subject to garbage collection. Sooner or later garbage collection will be activated and B will disappear from the collection.

By having a 'WeakReference' to an object, you are indicating that it is ok if the object dissappears.

'Finalization' is the name of the phase when garbage collection is invoked. And in our example, when B is deleted, a message is sent to the collection informing it of the demise of B.

Evaluate Program 48-3 to see an example of what happens to items only linked by a weak reference, in this case a 'WeakArray':


Program-48-3: (WeakArray, ObjectMemory; gc, finalization, 
garbage collection)
------------------------------------------------------------
| weakArray |
weakArray := WeakArray new: 3.
weakArray at: 1 put: 'aaa' copy.
weakArray at: 2 put: 'bbb' copy.
weakArray at: 3 put: 'ccc' copy.
weakArray inspect.
ObjectMemory garbageCollect
------------------------------------------------------------

Even though you can see that ('aaa' 'bbb' 'ccc') are stored in the array, the inspector inidicates the values of the first three items in the array are all zero. This is because garbage collection reclamed their space.

If you store 'aaa' in a 'WeakArray', the literal 'aaa' will have a 'StrongReference' to the 'WeakArray' from the literal frame of the method execution context. Therefore Program 48-1 uses a 'copy' rather than the literal itself to illustrate how objects can disappear.

The program invokes garbage collection explicitly. It is not really necessary, because 'aaa', 'bbb', and 'ccc', which were borne in Eden have only a short life and will be collected by the generation scavenger and not even be moved to current memory space.

Program 48-4 opens two inspector Windows, one is for 'strongArray' (Array) and another is for 'weakArray' (WeakArray).


Program-48-4: (WeakArray, Array, ObjectMemory; gc, 
finalization, garbage collection)
------------------------------------------------------------
| strongArray weakArray |
strongArray := Array new: 3.
strongArray at: 1 put: 'aaa' copy.
strongArray at: 2 put: 'bbb' copy.
strongArray at: 3 put: 'ccc' copy.
weakArray := WeakArray withAll: strongArray.
strongArray inspect.
weakArray inspect.
ObjectMemory garbageCollect
------------------------------------------------------------

This time you see 'aaa', 'bbb', 'ccc' in both the weak and the strong array. Actually they are the very same objects. Now evaluate this next message expressions in the right sub window of the 'strongArray' (Array) inspector.

------------------------------------------------------------
self at: 1 put: nil.
self at: 2 put: nil.
self at: 3 put: nil.
ObjectMemory garbageCollect
------------------------------------------------------------

The 'self' of the above messages is a 'strongArray ' (an instance of Array), so the contents of 'strongArray ' become (nil nil nil). The contents of 'weakArray ' (an instance of WeakArray) should now also be (0 0 0) because references of 'weakArray' are unlinked automatically references from the 'strongArray' are unlinked.

Program 48-5 is implemented for the above A,B,C objects example. Notice that 'bar' is a dependent object of the collection. And also notice that 'bar' receives a message of 'foo's death. Evaluate the program.


Program-48-5: (WeakArray, Array, ValueHolder, PluggableAdaptor, 
ObjectMemory; gc, finalization, garbage collection)
------------------------------------------------------------
| foo collection bar blee blue |
foo := 'aaa' copy.
blue := 'bbb' copy.
collection := WeakArray with: foo with: blue.
bar := PluggableAdaptor on: collection.
bar
        getBlock: [:model | false]
        putBlock: [:model :value | false]
        updateBlock:
                [:model :aspect :parameter |
                Transcript cr; show: 'Aspect:', aspect printString.
                aspect = #ElementExpired
                        ifTrue:
                                [Transcript cr.
                                Transcript show: 'Element has died.'.
                        Transcript show: ' Model: ', model printString].
                false].
collection addDependent: bar.
blee := ValueHolder with: foo.
blee inspect.
bar inspect.
ObjectMemory garbageCollect
------------------------------------------------------------

Two inspectors are raised. Verify that the following links exist. Notice that the collection has a 'WeakReference' to foo and blue.

------------------------------------------------------------------
bar (aPluggableAdaptor)  -- model --->  collection (aWeakArray)
collection (aWeakArray)  -- at: 1 --->  foo  ('aaa')
                         -- at: 2 --->  blue ('bbb')
blee (aValueHolder)      -- value --->  foo  ('aaa')
------------------------------------------------------------------

Soon after the inspectors are raised, you should see

        Element has died. Model: WeakArray ('aaa' 0)

in the Transcript window. Now we will unlink the 'StrongReference' from blee to foo. Evaluate the following in the right sub window of the inspector for blee (ValueHolder).

------------------------------------------------------------
self value: nil.
ObjectMemory garbageCollect
------------------------------------------------------------

'Element has died.' will print in the Transcript window indicating that the Pluggable Adaptor received an update message from the garbage collector. Step by step what happened is:

1) GC claims 'blue' and sends a message to the collection
2) 'blee' unlinks its reference to 'foo'
2) 'foo' becomes subject to garbage collection
3) Garage collection is activated
4) 'foo' is removed from the collection
5) A message of foo's demise is broadcast

'WeakReference' and 'Finalization' should be clear enough now for you to understand Program 48-6 without too much trouble.


Program-48-6: (WeakArray, Array, ValueHolder, PluggableAdaptor, 
ObjectMemory; gc, finalization, garbage collection)
------------------------------------------------------------
| foo collection blee bar |
foo := Array
                        with: 'aaa' copy
                        with: 'bbb' copy
                        with: 'ccc' copy.
collection := WeakArray withAll: foo.
blee := PluggableAdaptor on: collection.
blee
        getBlock: [:model | false]
        putBlock: [:model :value | false]
        updateBlock:
                [:model :aspect :parameter |
                aspect = #ElementExpired ifTrue: [model
                                nilAllCorpsesAndDo:
                                        [:i |
                                        Transcript cr.
                                        Transcript show: 'Element'.
                                        Transcript show: i printString.
                                        Transcript show: ' has died.']].
                false].
collection addDependent: blee.
bar := ValueHolder with: foo.
bar inspect.
blee inspect.
ObjectMemory garbageCollect
------------------------------------------------------------

After Program 48-6, evaluate the following expressions in the right sub window of the inspector of A (ValueHolder).

------------------------------------------------------------
self value at: 1 put: 'ddd'.
self value at: 2 put: 'eee'.
self value at: 3 put: 'fff'.
ObjectMemory garbageCollect
------------------------------------------------------------

Notice this time that the contents of the collection to which C refers are not (0 0 0) but (nil nil nil). The key is in the implementation of the 'nilAllCorpsesAndDo:' message. You can 'Browse Implementors Of...' to see that it sets each deleted item to nil.

By using inspectors, you have been able to observe the birth, growth, illness, death, and corpse of an object in keeping with the metaphor of a company mentioned above. In a manner of speaking 'WeakReference' corresponds to illness, 'Finalization' corresponds to death and a zero OOP corresponds to a corpse.

As a final example of 'WeakReference' and 'Finalization', imagine a resource management program for the host window system. Resource object examples are instances of ScheduledWindow, Pixmap and Mask. The resources of the host window system are temporarily lent to user applications and must eventually be returned to the host window system. However while a resource is in use by the application, it can not be returned. In other words the resources must only be returned when no one is using them. 'WeakReference' and 'Finalization' are a convenient way to handle this situation in which you want to manage a resource while it is being used, and then release it. It is a necessary mechanism for distributed parallel systems. You can see how it can control the birth and death of external objects which are distributed over a network.

There are two other classes related to 'WeakReference': 'WeakKeyAssociation' and 'WeakDictionary'. Experiment with your own classes to handle 'WeakReference'.


parent previous next question
Copyright (C) 1994-1996 by Atsushi Aoki
Translated by Kaoru Rin Hayashi & Brent N. Reeves