Can someone explain what a "weak" vs (I am guessing) "strong" reference is? I have been struggling with Garbage Collection for quite some time now and saw this on another list: "You'll need to add an instance variable to process and modify fork to record the origin. Currently processes don't remember their ancestor. I recommend you create a special fork that remembers ancestry, rather than modifying the default fork. You will potentially accumulate a lot of garbage otherwise. Also, you might consider making the reference from a process to its parent weak to allow the parent to be GC'ed when it terminates even if it has children."
I, too, am maintaining parent/child relationships in my application and have just been doing something like:
Parent>>createChild |child| child := Child new parent: self. ^child
I am assuming, given my troubles, that this is NOT a weak reference?!
Thank you,
Rob
On Sun, Jul 13, 2008 at 6:15 PM, Rob Rothwell r.j.rothwell@gmail.com wrote:
Can someone explain what a "weak" vs (I am guessing) "strong" reference is?
[snip]
I, too, am maintaining parent/child relationships in my application and have just been doing something like: Parent>>createChild |child| child := Child new parent: self. ^child I am assuming, given my troubles, that this is NOT a weak reference?!
Hi Rob, Have a look at the class comment on WeakArray: "WeakArray is an array which holds only weakly on its elements. This means whenever an object is only referenced by instances of WeakArray it will be garbage collected."
My understanding of this is that garbage collection is done by reference counting, and so the situation you described may result in parent and child forming a circular reference to each other, and so never being collected - but it depends on what you do with that return value.
I note that there are very few uses of any Weak* classes in the image, so it's likely that there is a better way of implementing what you're aiming for; eg the child could drop its direct parent reference, and do something like
Child>>parent ^ Parent allInstances detect: [ :each | each children includes: self ]
(or vice versa depending on which way you're more likely to traverse the relationship).
This is just me thinking out loud though - perhaps someone else could comment on best practice in this case. "Smalltalk Best Practice Patterns" is very useful in answering these types of questions, but my copy is in a box somewhere at the moment.
Hope this helps, Michael
"Michael" == Michael Davies mykdavies+squeak@gmail.com writes:
Michael> I note that there are very few uses of any Weak* classes in the image, Michael> so it's likely that there is a better way of implementing what you're Michael> aiming for; eg the child could drop its direct parent reference, and Michael> do something like
Child> parent Michael> ^ Parent allInstances detect: [ :each | each children includes: self ]
Michael> (or vice versa depending on which way you're more likely to traverse Michael> the relationship).
I'd argue though that a solution that involves #allInstances has a bit of code smell. For example, consider an XML node, looking for its parent. In a given parsed document, you'll likely have thousands of nodes, and it would be clearly inefficient to continually find the one parent by asking all of them. In that case though, weak refs probably weren't needed anyway, since each node can just contain its parent.
Michael> This is just me thinking out loud though - perhaps someone else could Michael> comment on best practice in this case. "Smalltalk Best Practice Michael> Patterns" is very useful in answering these types of questions, but my Michael> copy is in a box somewhere at the moment.
Absolutely. A clearly seminal book. My dog-eared copy is within reach, at least when I'm in my home office. Too bad Kent has gone off to the Java, and now C# realm, if I heard right.
Hello Michael,
Child>>>parent MD> ^ Parent allInstances detect: [ :each | each children includes: self ]
allInstances scans *every* object in the image which is slow.
The garbage collector needs a path to a root object (whatever that is) so a purely circular reference does not prevent garbage collection of parent and child.
On Mon, Jul 14, 2008 at 4:43 PM, Herbert König herbertkoenig@gmx.net wrote:
Hello Michael,
Child>>>parent MD> ^ Parent allInstances detect: [ :each | each children includes: self ]
allInstances scans *every* object in the image which is slow.
Ouch, I can see that it would be :-)
The garbage collector needs a path to a root object (whatever that is) so a purely circular reference does not prevent garbage collection of parent and child.
Thanks, that's interesting - does that mean that the parent-child linkage in Rob's example isn't the root cause of his problem?
Hello Michael,
MD> Thanks, that's interesting - does that mean that the parent-child MD> linkage in Rob's example isn't the root cause of his problem?
see Bert's reply, he knows why it is so, I only know that I do it all the time (circular links) and it never prevents GC.
On Mon, 14 Jul 2008 12:07:51 +0200 "Michael Davies" mykdavies+squeak@gmail.com wrote:
On Sun, Jul 13, 2008 at 6:15 PM, Rob Rothwell r.j.rothwell@gmail.com wrote:
Can someone explain what a "weak" vs (I am guessing) "strong" reference is?
[snip]
I, too, am maintaining parent/child relationships in my application and have just been doing something like: Parent>>createChild |child| child := Child new parent: self. ^child I am assuming, given my troubles, that this is NOT a weak reference?!
Hi Rob, Have a look at the class comment on WeakArray: "WeakArray is an array which holds only weakly on its elements. This means whenever an object is only referenced by instances of WeakArray it will be garbage collected."
My understanding of this is that garbage collection is done by reference counting, and so the situation you described may result in parent and child forming a circular reference to each other, and so never being collected - but it depends on what you do with that return value.
Squeak's garbage collector is a generational mark/sweep garbage collector. It does not use reference counting.
http://wiki.squeak.org/squeak/1469 (unfortunately the page has a dead URL in it).
Gulik.
A weak reference is simply a reference that will not prevent an object from being garbage collected. It is common to use a weak reference in back pointers when you know you are having circularities. It is practically a pattern, when building a hierarchy of objects, to make the parent pointer in parent child type structures a weak reference.
So how do you make a weak reference? You stick a WeakArray in as a holder. So in your parent/child objects you would write something like:
Node>>parent ^ parent ifNotNil: [parent first] ifNil: [parent]
Node>>parent: p parent := p ifNotNil: [WeakArray with: p] ifNil: [p]
thus using a WeakArray as a holder for the parent.
When a weak reference gets garbage collected, its weak references are set to nil first.
On Jul 13, 2008, at 9:15 AM, Rob Rothwell wrote:
Can someone explain what a "weak" vs (I am guessing) "strong" reference is? I have been struggling with Garbage Collection for quite some time now and saw this on another list:
"You'll need to add an instance variable to process and modify fork to record the origin. Currently processes don't remember their ancestor. I recommend you create a special fork that remembers ancestry, rather than modifying the default fork. You will potentially accumulate a lot of garbage otherwise. Also, you might consider making the reference from a process to its parent weak to allow the parent to be GC'ed when it terminates even if it has children."
I, too, am maintaining parent/child relationships in my application and have just been doing something like:
Parent>>createChild |child| child := Child new parent: self. ^child
I am assuming, given my troubles, that this is NOT a weak reference?!
Thank you,
Rob
Beginners mailing list Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
On Mon, Jul 14, 2008 at 11:42 AM, Todd Blanchard tblanchard@mac.com wrote:
So how do you make a weak reference? You stick a WeakArray in as a holder. So in your parent/child objects you would write something like:
Node>>parent ^ parent ifNotNil: [parent first] ifNil: [parent]
Node>>parent: p parent := p ifNotNil: [WeakArray with: p] ifNil: [p]
thus using a WeakArray as a holder for the parent.
When a weak reference gets garbage collected, its weak references are set to nil first.
Thank you! This is what I wanted to know; I'll give this a try, and see how it works for me...
So many Classes, so little time...
Rob
Am 14.07.2008 um 09:51 schrieb Rob Rothwell:
On Mon, Jul 14, 2008 at 11:42 AM, Todd Blanchard tblanchard@mac.com wrote: So how do you make a weak reference? You stick a WeakArray in as a holder. So in your parent/child objects you would write something like:
Node>>parent ^ parent ifNotNil: [parent first] ifNil: [parent]
Node>>parent: p parent := p ifNotNil: [WeakArray with: p] ifNil: [p]
thus using a WeakArray as a holder for the parent.
When a weak reference gets garbage collected, its weak references are set to nil first.
Thank you! This is what I wanted to know; I'll give this a try, and see how it works for me...
So many Classes, so little time...
Well, Todd certainly knows when he needs to introduce weak refs but a simple parent-child relation (say, in a tree) is *not* a good example for this. The parent reference in a child does not prevent it from being garbage-collected, unless there exist other references to it. You cut the child link and it's gone. But if there are indeed other references to the child weak refs would just mask the problem because the parent may get garbage-collected but the child is not. The problem in that case typically is not the parent/child links but those other references.
In a clean design you very rarely need weak refs. Also, you need to sprinkle your code with ifNil: tests because a weak ref can become nil any time.
- Bert -
On Mon, Jul 14, 2008 at 10:43:30PM -0700, Bert Freudenberg wrote:
In a clean design you very rarely need weak refs. Also, you need to sprinkle your code with ifNil: tests because a weak ref can become nil any time.
It is also worth mentioning that weak references can lead to performance problems, particularly if you use a lot of them. The process of cleaning up weak references happens in the background, and is not very efficient if a lot of weak references need to be scanned. The end result is that your Squeak image will gradually become very slow, for no obvious reason. Bert's observation on design is the best reason to avoid using weak references, but if you need more convincing, consider performance ;)
Dave
Hello cdrick,
c> All that sounds like "don't use weak reference" :)
.... unless you know exactly what you are doing.
"Herbert" == Herbert König herbertkoenig@gmx.net writes:
Herbert> Hello cdrick, c> All that sounds like "don't use weak reference" :)
Herbert> .... unless you know exactly what you are doing.
One possible use I haven't seen in this thread is to "keep notes" on a class you don't own (and don't want to change), without preventing them from being GC'ed normally.
For example, if I wanted to write a system watcher that noticed the comings and goings of Process objects, I'd likely keep a Dictionary keyed by the Process instance referencing the data of start times. However, I wouldn't want that key to keep the Process instance from being gc'ed, so I'd use a weak dictionary. This is how the classic "dependents" system works as well: the dependencies are in a WeakDictionary so that when the watched object goes away, the dependencies are also cleaned.
The alternative is to add a set of properties to the Process that others can stuff information, so that "Process allInstances" can get my process watcher what it needs instead.
Hello Randal,
RLS> dictionary. This is how the classic "dependents" system works as well: the RLS> dependencies are in a WeakDictionary so that when the watched object goes RLS> away, the dependencies are also cleaned.
thanks for some free education (no smiley, I mean it), now I'll do some homework and look up dependency.
I use it in some places without knowing of it's "weakness".
Am 15.07.2008 um 08:26 schrieb Herbert König:
Hello Randal,
RLS> dictionary. This is how the classic "dependents" system works as well: the RLS> dependencies are in a WeakDictionary so that when the watched object goes RLS> away, the dependencies are also cleaned.
thanks for some free education (no smiley, I mean it), now I'll do some homework and look up dependency.
I use it in some places without knowing of it's "weakness".
The dependents are weak only for "regular" objects. Proper Models handle their own dependents collection in a non-weak manner.
- Bert -
Bert Freudenberg a écrit :
Am 15.07.2008 um 08:26 schrieb Herbert König:
Hello Randal,
RLS> dictionary. This is how the classic "dependents" system works as well: the RLS> dependencies are in a WeakDictionary so that when the watched object goes RLS> away, the dependencies are also cleaned.
thanks for some free education (no smiley, I mean it), now I'll do some homework and look up dependency.
I use it in some places without knowing of it's "weakness".
The dependents are weak only for "regular" objects. Proper Models handle their own dependents collection in a non-weak manner.
- Bert -
Hmm, not really
"Warning: this example is stupid!" | tmp | tmp := Model new. tmp addDependent: #x. tmp addDependent: #y. tmp dependents class. "=> DependentsArray"
DependentsArray is a class that holds weakly to its elements...
The difference is that the DependentsArray itself don't have to pollute the global WeakIdentityKeyDictionary (Object classPool at: #DependentsFields).
But maybe we have just quit the beginners rails...
Nicolas
Am 15.07.2008 um 13:23 schrieb nicolas cellier:
Bert Freudenberg a écrit :
Am 15.07.2008 um 08:26 schrieb Herbert König:
Hello Randal,
RLS> dictionary. This is how the classic "dependents" system works as well: the RLS> dependencies are in a WeakDictionary so that when the watched object goes RLS> away, the dependencies are also cleaned.
thanks for some free education (no smiley, I mean it), now I'll do some homework and look up dependency.
I use it in some places without knowing of it's "weakness".
The dependents are weak only for "regular" objects. Proper Models handle their own dependents collection in a non-weak manner.
- Bert -
Hmm, not really
"Warning: this example is stupid!" | tmp | tmp := Model new. tmp addDependent: #x. tmp addDependent: #y. tmp dependents class. "=> DependentsArray"
DependentsArray is a class that holds weakly to its elements...
The difference is that the DependentsArray itself don't have to pollute the global WeakIdentityKeyDictionary (Object classPool at: #DependentsFields).
You are right, I was mislead by Object>>dependents ...
But maybe we have just quit the beginners rails...
... and you are right again.
- Bert -
Bert Freudenberg a écrit :
Am 15.07.2008 um 13:23 schrieb nicolas cellier:
Bert Freudenberg a écrit :
The dependents are weak only for "regular" objects. Proper Models handle their own dependents collection in a non-weak manner.
- Bert -
Hmm, not really
"Warning: this example is stupid!" | tmp | tmp := Model new. tmp addDependent: #x. tmp addDependent: #y. tmp dependents class. "=> DependentsArray"
DependentsArray is a class that holds weakly to its elements...
The difference is that the DependentsArray itself don't have to pollute the global WeakIdentityKeyDictionary (Object classPool at: #DependentsFields).
You are right, I was mislead by Object>>dependents ...
But maybe we have just quit the beginners rails...
... and you are right again.
- Bert -
While we are at it, here is a lesson i learned recently:
| weak obj | weak := WeakIdentityKeyDictionary new. "Create an Object" obj := Object new. "Add a weak reference to this Object" weak at: obj put: (Array with: obj). "This DoIt methods points to the Object via it's temporary variable. Clear this pointer, so that the Object can eventually be reclaimed" obj := nil. "Now garbageCollect to reclaim the weak references" Smalltalk garbageCollect. "Let us see if the Object was reclaimed:" ^weak size
Why the object obj was not reclaimed? Obviously, the WeakKeyAssociation value is not weak... It is a strong pointer and points strongly to obj through the Array...
Trivial, you might say. Well yes, it is just http://bugs.squeak.org/view.php?id=7119 in disguise and i find it nasty.
So be very carfull with Weak references - not only newbs - issues might definitely be advanced to track down...
Nicolas
On Tue, 15 Jul 2008 23:21:17 +0200, nicolas cellier wrote:
...
While we are at it, here is a lesson i learned recently:
| weak obj | weak := WeakIdentityKeyDictionary new.
"Create an Object" obj := Object new. "Add a weak reference to this Object" weak at: obj put: (Array with: obj). "This DoIt methods points to the Object via it's temporary variable. Clear this pointer, so that the Object can eventually be reclaimed" obj := nil. "Now garbageCollect to reclaim the weak references" Smalltalk garbageCollect. "Let us see if the Object was reclaimed:" ^weak size
Why the object obj was not reclaimed?
Perhaps because WeakIdentityKeyDictionary (as well as WeakKeyDictionary) instance variable is not initialized/assigned, as its name suggests something Weak* ;)
Do (WeakIdentityKeyDictionary new inspect) and check for Weak* things: none here. This is so in the .image version that I'm using right now, 'Squeak3.10.2', haven't checked others.
Obviously, the WeakKeyAssociation value is not weak... It is a strong pointer and points strongly to obj through the Array...
Or it's just a Weak* instance variable bug :( anybody confirm this?
Trivial, you might say. Well yes, it is just http://bugs.squeak.org/view.php?id=7119 in disguise and i find it nasty.
So be very carfull with Weak references - not only newbs - issues might definitely be advanced to track down...
Nicolas
"nicolas" == nicolas cellier ncellier@ifrance.com writes:
nicolas> But maybe we have just quit the beginners rails...
I think the moment you mention "Weak", you're already outside beginner space. :)
Randal L. Schwartz a écrit :
"nicolas" == nicolas cellier ncellier@ifrance.com writes:
nicolas> But maybe we have just quit the beginners rails...
I think the moment you mention "Weak", you're already outside beginner space. :)
That's the quality of our Squeak beginners. They bring really advanced topics to this list.
On Tue, Jul 15, 2008 at 5:47 PM, nicolas cellier ncellier@ifrance.com wrote:
Randal L. Schwartz a écrit :
"nicolas" == nicolas cellier ncellier@ifrance.com writes:
>
nicolas> But maybe we have just quit the beginners rails...
I think the moment you mention "Weak", you're already outside beginner space. :)
That's the quality of our Squeak beginners. They bring really advanced topics to this list.
Well, I asked the question in the first place because the minute you try to do something "real," you run into, well, real problems that always seem to have an "advanced" answer!
I always figure that points to my true beginner-ness, though!
Thanks for all the theory...
Rob
Beginners mailing list Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
On Tue, Jul 15, 2008 at 2:39 PM, cdrick cdrick65@gmail.com wrote:
All that sounds like "don't use weak reference" :)
Cédrick
A nice clear summary!
Thanks to all who have posted on this topic - it's been a very useful discussion.
Michael
beginners@lists.squeakfoundation.org