This is actually quite similar to what I thought about for a more robust finalization solution. My thought was that you could just use linked lists (which have operations that are already supported by the VM for process management) and then make a weak subclass of Link that holds the object to be watched plus the finalizer for the object. When the VM traces such a link it puts it onto a VM-level finalization list and signals the finalization semaphore. The finalization process then pulls the entries from the list and calls the finalize method on it.
Cheers, - Andreas
Igor Stasenko wrote:
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.
The problem:
- 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 collection. 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 garbage.
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' classVariableNames: '' poolDictionaries: '' category: 'Collections-Weak'
so, that VM can check this special kind of weak reference in ObjectMemory>>finalizeReference: method.
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 instanceVariableNames: 'head' classVariableNames: '' poolDictionaries: '' category: 'Collections-Weak'
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 instanceVariableNames: 'executor' classVariableNames: '' poolDictionaries: '' category: 'Collections-Weak' ...
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.