oops...
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 26 March 2006 at 12:56:17 am'! !WeakArray class methodsFor: 'private' stamp: 'cds 3/25/2006 15:01'! compactFinalizationDependents: minimumSize | tmp index | tmp := WeakArray new: minimumSize + 10. index := 1. FinalizationLock critical: [FinalizationDependents do: [:dependent | dependent ifNotNil: [tmp at: index put: dependent. index := index + 1]]. FinalizationDependents := tmp] ifError: [:msg :rcvr | rcvr error: msg]! ! !WeakArray class methodsFor: 'private' stamp: 'cds 3/26/2006 00:56'! finalizationProcess | nilEntries | [true] whileTrue: [nilEntries := 0. FinalizationSemaphore wait. FinalizationLock critical: [FinalizationDependents do: [:weakDependent | weakDependent ifNotNil: [weakDependent finalizeValues. "***Following statement is required to keep weakDependent from holding onto its value as garbage.***" weakDependent _ nil] ifNil: [nilEntries := nilEntries + 1]]] ifError: [:msg :rcvr | rcvr error: msg]. "Check if we should compact the array" (nilEntries > (FinalizationDependents size quo: 4) and: [FinalizationDependents size > 10]) ifTrue: [self compactFinalizationDependents: (FinalizationDependents size - nilEntries)] ]. ! ! |
In reply to this post by Andreas.Raab
I've started to make an attempt at this but I didn't get far....I've got
a class which mimics WeakValueAssociation but has nextLink and executor ivars. Andreas Raab wrote: > signalFinalization: oop > (self fetchClassOf: oop) == self classFinalizer ifTrue:[ > self addLastLink: oop toList: self finalizerList. > self forceInterruptCheck. > pendingFinalizationSignals _ pendingFinalizationSignals + 1. > ]. > > addLastLink:toList: is defined in Interpreter but the current finalization code resides in ObjectMemory. Should I a) just send it anyway...yuk? b) move it up? c) duplicate it (with different name?) in ObjectMemory? Also, how do I safely unlink elements from the "ReadyForFinalization" list in Smalltalk? We will always be removing from the front of the list. I looked at Process which simply sends #remove: but this seems dangerous if a GC should occur during execution of this method (there is a race condition related to the "firstLink"): remove: aLink ifAbsent: aBlock "Remove aLink from the receiver. If it is not there, answer the result of evaluating aBlock." | tempLink | aLink == firstLink ifTrue: [firstLink _ aLink nextLink. "if GC happens here then lastLink is invalid..." aLink == lastLink ifTrue: [lastLink _ nil]] ifFalse: [tempLink _ firstLink. [tempLink == nil ifTrue: [^aBlock value]. tempLink nextLink == aLink] whileFalse: [tempLink _ tempLink nextLink]. tempLink nextLink: aLink nextLink. aLink == lastLink ifTrue: [lastLink _ tempLink]]. aLink nextLink: nil. ^aLink > WeakRegistry and other users would be fairly straighforward to deal > with - they'd just store (strong references to) Finalizer's instead of > (weak) object references and the finalizer would remove itself from > the registry. No big deal, really. While _some_ users of "Weak" structures won't care about finalization, it looks like many will. The "dictionary-like" objects all rehash whenever one of their keys is collected. Seaside, in particular, does this: dict _ WeakIdentityKeyDictionary new: aNumber. WeakArray addWeakDependent: dict. so that dict gets rehashed whenever needed. All that we're doing now is providing a hint as to who was affected (so we'll only rehash dictionaries which had values reclaimed) but suppose, for example, that the same dictionary had multiple collected keys, now instead of rehashing once we'll have to be a bit cleaver or we're going to consider rehashing for each reclaimed object. That is, we'll run WeakKeyDictionary>>finalizeValues for each collected object that corresponds to a key in this dictionary. Old Scheme --------------------- Loops over all WeakArray's FinalizationDependents sending finalizeValues since it doesn't know who cares about that object New Scheme ----------------------- Loops removing elements from Finalizable list running the executor for each (these executors presumably send #finalizeValues to dictionary if they correspond to a dictionary entry) Since almost all of the of the elements of FinalizationDependents (in a Seaside image) are WeakIdentityKeyDictionaries there will be some savings but not as much as I had hoped and I think this method would be particularly wasteful if there isn't some way to coalesce sends of #finalizeValues. David |
David Shaffer wrote:
> addLastLink:toList: is defined in Interpreter but the current > finalization code resides in ObjectMemory. Should I > > a) just send it anyway...yuk? > b) move it up? > c) duplicate it (with different name?) in ObjectMemory? a) Send it anyway. ObjectMemory and Interpreter are always run together - the distinction between them (while useful on a conceptual level) is irrelevant in practice. > Also, how do I safely unlink elements from the "ReadyForFinalization" > list in Smalltalk? We will always be removing from the front of the > list. I looked at Process which simply sends #remove: but this seems > dangerous if a GC should occur during execution of this method (there is > a race condition related to the "firstLink"): I think we'll need a primitive for that, since primitives are run atomically (so there isn't a GC issue unless you create one ;-) >> WeakRegistry and other users would be fairly straighforward to deal >> with - they'd just store (strong references to) Finalizer's instead of >> (weak) object references and the finalizer would remove itself from >> the registry. No big deal, really. > > While _some_ users of "Weak" structures won't care about finalization, > it looks like many will. The "dictionary-like" objects all rehash > whenever one of their keys is collected. Seaside, in particular, does this: > > dict _ WeakIdentityKeyDictionary new: aNumber. > WeakArray addWeakDependent: dict. > > so that dict gets rehashed whenever needed. All that we're doing now is > providing a hint as to who was affected (so we'll only rehash > dictionaries which had values reclaimed) but suppose, for example, that > the same dictionary had multiple collected keys, now instead of > rehashing once we'll have to be a bit cleaver or we're going to consider > rehashing for each reclaimed object. That is, we'll run > WeakKeyDictionary>>finalizeValues for each collected object that > corresponds to a key in this dictionary. Hell, no! What we'll do is instead of just sending #finalize is that we'll send #finalize: with the finalizer as an argument (which by default just invokes #finalize on the receiver) so that registries can remove just the entry that was finalized. Something like here: Object>>finalize: aFinalizer "The receiver, being the executor for the value stored in aFinalizer is being asked to perform finalization. By default, we ignore the argument and simply call #finalize; but subclasses can use that information for good purpose." ^self finalize WeakArray>>finalize: aFinalizer self removeEntry: aFinalizer. "you get the idea" In the (absolute worst and unlikely) case that passing the finalizer along isn't enough we can add an extra slot for an object receiving notifications about the finalization (but it's probably unnecessary). > Old Scheme > --------------------- > Loops over all WeakArray's FinalizationDependents sending finalizeValues > since it doesn't know who cares about that object > > New Scheme > ----------------------- > Loops removing elements from Finalizable list running the executor for > each (these executors presumably send #finalizeValues to dictionary if > they correspond to a dictionary entry) > > Since almost all of the of the elements of FinalizationDependents (in a > Seaside image) are WeakIdentityKeyDictionaries there will be some > savings but not as much as I had hoped and I think this method would be > particularly wasteful if there isn't some way to coalesce sends of > #finalizeValues. Nope. It'll be something like a #removeKey: per finalized entry. I can guarantee that - if it were different I wouldn't be interested at all ;-) Cheers, - Andreas |
Free forum by Nabble | Edit this page |