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. -- Best regards, Igor Stasenko AKA sig. |
Igor, read up on ephemerons. They're a fine way of doing instance-based finalization in Smalltalk, designed originally by George Boswith and implemented in Digitalk's Smalltalk. They're "smart" associations which get queued for finalization when the only references to their key are through ephemerons. They've been in the VW VM since I implemented them in about 2000, and they're actually being used up in the image now.
On Wed, Apr 22, 2009 at 3:19 PM, Igor Stasenko <[hidden email]> wrote:
|
In reply to this post by Igor Stasenko
Well there was the Ephemerons stuff you can add too http://map.squeak.org/package/fe2a35f5-3f97-431e-8596-58e810aa3c72 ian had a version he pushed out a couple of years, back which was retracted because it caused VM crashs, but later was proven to be an off by 1 C/slang coding error. But no-one I think had the courage to inflict back onto the community. Er so how would compatibilty work with this new way given an image which may or may not include image side companion code. -- = = = ======================================================================== John M. McIntosh <[hidden email]> Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com = = = ======================================================================== |
On Wed, Apr 22, 2009 at 3:50 PM, John M McIntosh <[hidden email]> wrote:
We'd still need to support weak arrays. But Ephemerons allow instance-based finalization, so they're a big step up on the postmortem finalization offered by weak arrays.
The current state of Cog is that with simple code generation and machine-code floating-point primitives the nbody benchmark form the computer language shootout is spending 40% of entire execution time in the incremental GC. So my next target will be te new two-word object header and a scavenger rather than a deferred code generator. I'm thinking of looking closely at the V8 GC (Lars Bak's presentation at Microsoft last week) and I could probably add ephemerons to that in a second rev.
|
In reply to this post by Eliot Miranda-2
2009/4/23 Eliot Miranda <[hidden email]>: > > Igor, > read up on ephemerons. They're a fine way of doing instance-based finalization in Smalltalk, designed originally by George Boswith and implemented in Digitalk's Smalltalk. They're "smart" associations which get queued for finalization when the only references to their key are through ephemerons. They've been in the VW VM since I implemented them in about 2000, and they're actually being used up in the image now. > Ephemerons require an additional GC phase, which i think adds much more complexity to GC comparing to what i propose. If we care only about instance-based finalization, in its current state, then i think that what i have propose will do it just well, except the cases where value refers directly (or indirectly) to key (so it can't be GCed). But sure, it would be better to have ephemerons :) > On Wed, Apr 22, 2009 at 3:19 PM, Igor Stasenko <[hidden email]> 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. >> >> >> -- >> Best regards, >> Igor Stasenko AKA sig. > > > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Igor Stasenko
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. > > |
2009/4/23 Andreas Raab <[hidden email]>: > > 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. > Yes, quite similar. I thought about using a globally registered list (in special objects table), where VM could stockpile all weak refs pending for finalization. But then i thought, that decentralized version of it can be even better - a developers could organize own list(s) and free choose own criteria, like at which point they need to visit own list(s) and flush them. > 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. >> >> > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by johnmci
2009/4/23 John M McIntosh <[hidden email]>: > > Well there was the Ephemerons stuff you can add too > > http://map.squeak.org/package/fe2a35f5-3f97-431e-8596-58e810aa3c72 > > ian had a version he pushed out a couple of years, back which was retracted > because it > caused VM crashs, but later was proven to be an off by 1 C/slang coding > error. > But no-one I think had the courage to inflict back onto the community. > > > Er so how would compatibilty work with this new way given an image which may > or may not include image side companion code. > I presume this is a question? If image don't have a class in special objects array, which should represent a class for such kind of weak references, then it will never get into that code, because (oop class isKindOf: nil "== WeakReferenceWithNotification ") will always be false. So, VM+image will behave exactly as in older versions of VM. > > -- > =========================================================================== > John M. McIntosh <[hidden email]> > Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com > =========================================================================== > > > > -- Best regards, Igor Stasenko AKA sig. |
2009/4/23 Igor Stasenko <[hidden email]>: > 2009/4/23 John M McIntosh <[hidden email]>: >> >> Well there was the Ephemerons stuff you can add too >> >> http://map.squeak.org/package/fe2a35f5-3f97-431e-8596-58e810aa3c72 >> >> ian had a version he pushed out a couple of years, back which was retracted >> because it >> caused VM crashs, but later was proven to be an off by 1 C/slang coding >> error. >> But no-one I think had the courage to inflict back onto the community. >> >> >> Er so how would compatibilty work with this new way given an image which may >> or may not include image side companion code. >> > > I presume this is a question? > If image don't have a class in special objects array, which should > represent a class for such kind of weak references, then it will never > get into that code, because > (oop class isKindOf: nil "== WeakReferenceWithNotification ") will > always be false. > So, VM+image will behave exactly as in older versions of VM. > Things not so bright, if you run an image which expecting new semantics on VMs which don't supports it. Then it could use a fallback version of code (and handle things in a way, how it currently done). It then will need to check if new capability is available or not at image startup phase. >> >> -- >> =========================================================================== >> John M. McIntosh <[hidden email]> >> Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com >> =========================================================================== > > -- > Best regards, > Igor Stasenko AKA sig. > -- Best regards, Igor Stasenko AKA sig. |
Free forum by Nabble | Edit this page |