In recent topic on Seaside list, someone has asked, why Seasider's
abandon the idea of using weak references (and use finalization
technique when they die).
The main issue was the slowness of weak finalization process
implemented in Squeak.
- sometimes developer needs to get a notification from system when
particular object become garbage, so an additional processing could be
activated, called finalization.
How things currently working:
Squeak provides a default finalization scheme implemented by
WeakRegistry class, where one could register a pair of weak reference
and executor. Its connected with finalization process , which governed
by WeakArray class.
Upon each GC, the finalization process awakes and sending
#finalizeValues to all objects, registered in FinalizationDependents
When a WeakRegistry receives this message, it iterates over own
WeakIdentityKeyDictionary instance to find a pairs, for which key
(weak ref) became nil, and sends #finalize to the value (executor).
The problem with such approach, is a linear time consumption spent for
scanning all registered key>value pairs.
If you have thousands of objects registered in that way, while only
few of them could become garbage, the finalization process still will
spend a fair amount of time, trying to determine which ones became
To eliminate this waste, we need to implement a scheme in VM, which
can help us to reach only those objects which is died during current
GC cycle, leaving rest untouched.
Here is what i'd like to propose:
- add a special class
Object weakSubclass: #WeakReferenceWithNotification
instanceVariableNames: 'list next'
so, that VM can check this special kind of weak reference in
A 'list' ivar can point to any object, we only need to be sure it
having at least one slot to hold a list head:
Object subclass: #FinalizationList
now, all we need is to modify #finalizeReference: method, to do
following at the moment of storing nil pointer:
" this is not actually the slang code, just to illustrate what it does "
(oop class isKindOf: WeakReferenceWithNotification) ifTrue: [
| list |
list := oop at: ListSlotIndex.
oop at: NextSlotIndex put: (list at: HeadSlotIndex).
list at: HeadSlotIndex put: oop.
What it does, it simply links given oop to the list.
And as you may suppose, if we have initial state:
- list with head == nil
- multiple instances with WeakReferenceWithNotification , all pointing
to our list, and having a weak refs,
then after GC, if some of the refs become nilled, in a list's head we
will have a list of weak references we need to finalize (or do
anything else we want to).
Then a finalization process in case of WeakRegistry, don't needs to go
through all weak references which are registered in itself, instead it
could simply do:
"suppose we use a subclass "
WeakReferenceWithNotification weakSubclass: #WeakReferenceWithExecutor
ref := list head.
ref notNil whileTrue: [
ref executor finalize.
ref := ref next.
list head: nil.
P.S. Me hopes ;) , that i successfully shown that the actual changes
to VM is quite simple and minimal. But effects of such change could
have a major impact on a finalization scheme performance.
Igor Stasenko AKA sig.