Hello, There's something I don't understand about
ephemerons. This is an experiment I did: | assoc | assoc :=
WeakKeyAssociation key:
Object new value:
'something'. ObjectMemory
globalGarbageCollect. Before I run this, I put a break point in
the #mourn method on WeakKeyAssociation. mourn <BREAK
POINT> "On
mourning simply remove the reference to the key and the value." self
key: nil value: nil Then I run it, and when I get into the
mourn method, the key of the WeakKeyAssociation is still filled in. Isn’t that strange? Because now I can
still create references to the #key even though the WeakKeyAssociation (or an
Ephemeron) thinks it was the only one having a reference to it. An EphemeronDictionary
for instance removes the key from itself when an Ephemeron gets the #mourn
method, but I would think that if during the process of the #mourn method
another process would become active, it could create references to the key causing
the EphemeronDictionary to still remove it, even though it shouldn't have
causing all kinds of problems. Am I seeing this correct? Is this to be
expected from ephemerons/EphemeronDictionary? Isn't that a dangerous property? Mark _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
At the point when #mourn is queued to be sent, there are no
other references to the key. The method for #mourn is not supposed to go
ahead and create new references. Also, there should be no attempts to
grabbing the keys of ephemerons for the reasons you describe. You may want
to read the original ephemerons paper for the rationale behind their
existence.
From:
[hidden email] [mailto:[hidden email]] On Behalf Of
Mark Plas
Sent: Thursday, July 09, 2009 1:20 AM To: [hidden email] Subject: [vwnc] Question about Ephemerons Hello, There's something I don't understand about
ephemerons. This is an experiment I
did: | assoc
| assoc :=
WeakKeyAssociation
key: Object new
value: 'something'. ObjectMemory
globalGarbageCollect. Before I run this, I put a break point in
the #mourn method on WeakKeyAssociation. mourn
<BREAK POINT>
"On mourning simply remove the reference to the key and the
value."
self key: nil value: nil Then I run it, and when I get into the mourn
method, the key of the WeakKeyAssociation is still filled
in. Isn’t that strange? Because now I can still
create references to the #key even though the WeakKeyAssociation (or an
Ephemeron) thinks it was the only one having a reference to it. An
EphemeronDictionary for instance removes the key from itself when an Ephemeron
gets the #mourn method, but I would think that if during the process of the
#mourn method another process would become active, it could create references to
the key causing the EphemeronDictionary to still remove it, even though it
shouldn't have causing all kinds of problems. Am I seeing this correct? Is this to be
expected from ephemerons/EphemeronDictionary? Isn't that a dangerous
property? Mark _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Thanks Andres, I'm trying to get an
idea of the kinds of things that can go wrong with Ephemerons, so I wrote some code: | d cnt obj temp i | d := EphemeronDictionary new. obj := Object new. d at: obj put: 'something'. obj := nil. i := 0. [temp := nil. i := i + 1. d associationsDo: [:assoc | temp := assoc key]. cnt := 0. d associationsDo: [:assoc | cnt := cnt + 1]. (cnt = 0 and: [temp notNil]) ifTrue: [self error:
'Element removed after ', i printString, ' iterations.']. cnt
> 0] whileTrue. When I execute this a
few times (do-it), it always results in an error. What does it do? I
create an EphemeronDictionary, add an element and then nil the reference to the
key so that the element in the dictionary can be removed via garbage collection. From then on I always
run over the associations and get a strong reference to the key (temp := assoc
key). After that I again run over the associations and count the number of
items in the Dictionary. When I have a strong
reference to the key and there are no more elements in the dictionary I raise
an error, because this means that an element has been GC-ed and removed from
the dictionary even though it shouldn't have been. Does this mean that
you should only use the key-accessing protocol on an EphemeronDictionary (at:,
at:ifAbsent: )? In my case, I'm just enumerating the elements, fooling the
dictionary that there were no more references. The same probably goes for #allInstances. Do you know of other 'leaks'
to watch out for? Mark From: [hidden email]
[mailto:[hidden email]] On Behalf Of Valloud, Andres At the point when #mourn is queued to be sent, there are no other
references to the key. The method for #mourn is not supposed to go ahead
and create new references. Also, there should be no attempts to grabbing
the keys of ephemerons for the reasons you describe. You may want to read
the original ephemerons paper for the rationale behind their existence. From: [hidden email]
[mailto:[hidden email]] On Behalf Of Mark Plas Hello, There's something I don't understand about
ephemerons. This is an experiment I did: | assoc | assoc :=
WeakKeyAssociation
key: Object new
value: 'something'. ObjectMemory globalGarbageCollect. Before I run this, I put a break point in
the #mourn method on WeakKeyAssociation. mourn
<BREAK POINT>
"On mourning simply remove the reference to the key and the value."
self key: nil value: nil Then I run it, and when I get into the
mourn method, the key of the WeakKeyAssociation is still filled in. Isn’t that strange? Because now I can
still create references to the #key even though the WeakKeyAssociation (or an
Ephemeron) thinks it was the only one having a reference to it. An
EphemeronDictionary for instance removes the key from itself when an Ephemeron
gets the #mourn method, but I would think that if during the process of the
#mourn method another process would become active, it could create references
to the key causing the EphemeronDictionary to still remove it, even though it
shouldn't have causing all kinds of problems. Am I seeing this correct? Is this to be
expected from ephemerons/EphemeronDictionary? Isn't that a dangerous property? Mark _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Mark, clearly obj was not collected because it's held by temp. Most
likely, what happened was that some form of GC detected that obj was nil and queued the corresponding ephemeron for finalization. After that happened, temp points to the key and creates a strong reference. Nevertheless, since finalization is not synchronous with GC, it may happen a while after GC queues an ephemeron for finalization. Again, the idea with ephemerons is not to unnecessarily grab on to their keys. Note that the asynchronous nature of finalization can cause additional weirdness in rare cases. Earlier yesterday I found that if you push really hard, you can add an ephemeron to the finalization queue multiple times. Basically, you keep flipping its ephemeronness and running the IGC. Eventually, you'll manage enough flips and IGC loops between two finalization process runs, and now the same ephemeron will be mourned two or more times. I'd guess this problem hardly ever happens (I forced it with a stress test), but it's wrong anyway. I am waiting for customer feedback to make sure the planned fix is acceptable. Mark Plas wrote: > > Thanks Andres, > > > > I'm trying to get an idea of the kinds of things that can go wrong > with Ephemerons, so I wrote some code: > > > > > > | d cnt obj temp i | > > d := EphemeronDictionary new. > > obj := Object new. > > d at: obj put: 'something'. > > obj := nil. > > i := 0. > > [temp := nil. > > i := i + 1. > > d associationsDo: [:assoc | temp := assoc key]. > > cnt := 0. > > d associationsDo: [:assoc | cnt := cnt + 1]. > > (cnt = 0 and: [temp notNil]) ifTrue: [self error: 'Element removed > after ', i printString, ' iterations.']. > > cnt > 0] whileTrue. > > > > > > When I execute this a few times (do-it), it always results in an error. > > > > What does it do? I create an EphemeronDictionary, add an element and > then nil the reference to the key so that the element in the > dictionary can be removed via garbage collection. > > From then on I always run over the associations and get a strong > reference to the key (temp := assoc key). After that I again run over > the associations and count the number of items in the Dictionary. > > When I have a strong reference to the key and there are no more > elements in the dictionary I raise an error, because this means that > an element has been GC-ed and removed from the dictionary even though > it shouldn't have been. > > > > Does this mean that you should only use the key-accessing protocol on > an EphemeronDictionary (at:, at:ifAbsent: )? In my case, I'm just > enumerating the elements, fooling the dictionary that there were no > more references. The same probably goes for #allInstances. > > > > Do you know of other 'leaks' to watch out for? > > > > Mark > > > > *From:* [hidden email] [mailto:[hidden email]] *On > Behalf Of *Valloud, Andres > *Sent:* donderdag 9 juli 2009 10:31 > *To:* vwnc NC > *Subject:* Re: [vwnc] Question about Ephemerons > > > > At the point when #mourn is queued to be sent, there are no other > references to the key. The method for #mourn is not supposed to go > ahead and create new references. Also, there should be no attempts to > grabbing the keys of ephemerons for the reasons you describe. You may > want to read the original ephemerons paper for the rationale behind > their existence. > > > > ------------------------------------------------------------------------ > > *From:* [hidden email] [mailto:[hidden email]] *On > Behalf Of *Mark Plas > *Sent:* Thursday, July 09, 2009 1:20 AM > *To:* [hidden email] > *Subject:* [vwnc] Question about Ephemerons > > Hello, > > > > There's something I don't understand about ephemerons. > > > > This is an experiment I did: > > > > | assoc | > > assoc := WeakKeyAssociation > > key: Object new > > value: 'something'. > > ObjectMemory globalGarbageCollect. > > > > > > > > Before I run this, I put a break point in the #mourn method on > WeakKeyAssociation. > > > > mourn > > <BREAK POINT> > > "On mourning simply remove the > reference to the key and the value." > > self key: nil value: nil > > > > Then I run it, and when I get into the mourn method, the key of the > WeakKeyAssociation is still filled in. > > > > Isn’t that strange? Because now I can still create references to the > #key even though the WeakKeyAssociation (or an Ephemeron) thinks it > was the only one having a reference to it. An EphemeronDictionary for > instance removes the key from itself when an Ephemeron gets the #mourn > method, but I would think that if during the process of the #mourn > method another process would become active, it could create references > to the key causing the EphemeronDictionary to still remove it, even > though it shouldn't have causing all kinds of problems. > > > > Am I seeing this correct? Is this to be expected from > ephemerons/EphemeronDictionary? Isn't that a dangerous property? > > > > Mark > vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
" clearly obj was not collected because it's held by temp"
Yes, I didn't mean to say the object was GC-ed, I meant to say it was removed from the Dictionary even though there was still a strong reference to it. But it turns out that this is how Ephemerons are supposed to work. So as long as you don't try to obtain references to the keys in some indirect way, an EphemeronDictionary is safe to use, though it may not always be clear what is to be understood by 'indirect way' (like #associationsDo: does). Thanks for your explanation, Mark -----Original Message----- From: [hidden email] [mailto:[hidden email]] On Behalf Of Andres Valloud Sent: donderdag 9 juli 2009 12:14 To: [hidden email] Subject: Re: [vwnc] Question about Ephemerons Mark, clearly obj was not collected because it's held by temp. Most likely, what happened was that some form of GC detected that obj was nil and queued the corresponding ephemeron for finalization. After that happened, temp points to the key and creates a strong reference. Nevertheless, since finalization is not synchronous with GC, it may happen a while after GC queues an ephemeron for finalization. Again, the idea with ephemerons is not to unnecessarily grab on to their keys. Note that the asynchronous nature of finalization can cause additional weirdness in rare cases. Earlier yesterday I found that if you push really hard, you can add an ephemeron to the finalization queue multiple times. Basically, you keep flipping its ephemeronness and running the IGC. Eventually, you'll manage enough flips and IGC loops between two finalization process runs, and now the same ephemeron will be mourned two or more times. I'd guess this problem hardly ever happens (I forced it with a stress test), but it's wrong anyway. I am waiting for customer feedback to make sure the planned fix is acceptable. Mark Plas wrote: > > Thanks Andres, > > > > I'm trying to get an idea of the kinds of things that can go wrong > with Ephemerons, so I wrote some code: > > > > > > | d cnt obj temp i | > > d := EphemeronDictionary new. > > obj := Object new. > > d at: obj put: 'something'. > > obj := nil. > > i := 0. > > [temp := nil. > > i := i + 1. > > d associationsDo: [:assoc | temp := assoc key]. > > cnt := 0. > > d associationsDo: [:assoc | cnt := cnt + 1]. > > (cnt = 0 and: [temp notNil]) ifTrue: [self error: 'Element removed > after ', i printString, ' iterations.']. > > cnt > 0] whileTrue. > > > > > > When I execute this a few times (do-it), it always results in an error. > > > > What does it do? I create an EphemeronDictionary, add an element and > then nil the reference to the key so that the element in the > dictionary can be removed via garbage collection. > > From then on I always run over the associations and get a strong > reference to the key (temp := assoc key). After that I again run over > the associations and count the number of items in the Dictionary. > > When I have a strong reference to the key and there are no more > elements in the dictionary I raise an error, because this means that > an element has been GC-ed and removed from the dictionary even though > it shouldn't have been. > > > > Does this mean that you should only use the key-accessing protocol on > an EphemeronDictionary (at:, at:ifAbsent: )? In my case, I'm just > enumerating the elements, fooling the dictionary that there were no > more references. The same probably goes for #allInstances. > > > > Do you know of other 'leaks' to watch out for? > > > > Mark > > > > *From:* [hidden email] [mailto:[hidden email]] *On > Behalf Of *Valloud, Andres > *Sent:* donderdag 9 juli 2009 10:31 > *To:* vwnc NC > *Subject:* Re: [vwnc] Question about Ephemerons > > > > At the point when #mourn is queued to be sent, there are no other > references to the key. The method for #mourn is not supposed to go > ahead and create new references. Also, there should be no attempts to > grabbing the keys of ephemerons for the reasons you describe. You may > want to read the original ephemerons paper for the rationale behind > their existence. > > > > ------------------------------------------------------------------------ > > *From:* [hidden email] [mailto:[hidden email]] *On > Behalf Of *Mark Plas > *Sent:* Thursday, July 09, 2009 1:20 AM > *To:* [hidden email] > *Subject:* [vwnc] Question about Ephemerons > > Hello, > > > > There's something I don't understand about ephemerons. > > > > This is an experiment I did: > > > > | assoc | > > assoc := WeakKeyAssociation > > key: Object new > > value: 'something'. > > ObjectMemory globalGarbageCollect. > > > > > > > > Before I run this, I put a break point in the #mourn method on > WeakKeyAssociation. > > > > mourn > > <BREAK POINT> > > "On mourning simply remove the > reference to the key and the value." > > self key: nil value: nil > > > > Then I run it, and when I get into the mourn method, the key of the > WeakKeyAssociation is still filled in. > > > > Isn't that strange? Because now I can still create references to the > #key even though the WeakKeyAssociation (or an Ephemeron) thinks it > was the only one having a reference to it. An EphemeronDictionary for > instance removes the key from itself when an Ephemeron gets the #mourn > method, but I would think that if during the process of the #mourn > method another process would become active, it could create references > to the key causing the EphemeronDictionary to still remove it, even > though it shouldn't have causing all kinds of problems. > > > > Am I seeing this correct? Is this to be expected from > ephemerons/EphemeronDictionary? Isn't that a dangerous property? > > > > Mark > vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Andres Valloud-6
I don't think it's reasonable to say that #mourn is not
supposed to go and create new references. It's probably not a great idea,
but it's the sort of thing that might happen very easily. For example,
simply writing mourn as
self methodThatIForgotToActuallyImplement. will bring up a debugger, and cause all kinds of strong references. In general, with things that are finalized by ephemerons, the policy should be to write the finalization methods such that it is safe to call them more than once. If we run arbitrary user code once those objects are queued for garbage collection, that user code may end up, intentionally or otherwise, causing the objects not to be garbage collected. And then, presumably, at some later point, they will be. This is a slight burden on the author of the code, but not that difficult, and usually amounts to nil checks. The advantage of this approach is that you actually get to write the finalization code on the object being finalized. The pre-ephemeron finalization code did not have this property. You got notified only _after_ the object was garbage collected. That was in some sense a nice property, but one downside was that for finalization you had to register some other object in a dictionary somewhere to get the notification. In practice, some other object usually meant a shallow copy of the object being finalized, and the registration and management of that was also a burden. At 04:31 AM 7/9/2009, Valloud, Andres wrote: Content-class: urn:content-classes:messageAt the point when #mourn is queued to be sent, there are no other references to the key. The method for #mourn is not supposed to go ahead and create new references. Also, there should be no attempts to grabbing the keys of ephemerons for the reasons you describe. You may want to read the original ephemerons paper for the rationale behind their existence. From: [hidden email] [[hidden email]] On Behalf Of Mark Plas Sent: Thursday, July 09, 2009 1:20 AM To: [hidden email] Subject: [vwnc] Question about Ephemerons Hello, There's something I don't understand about ephemerons. This is an experiment I did: | assoc | assoc := WeakKeyAssociation key: Object new value: 'something'. ObjectMemory globalGarbageCollect. Before I run this, I put a break point in the #mourn method on WeakKeyAssociation. mourn <BREAK POINT> "On mourning simply remove the reference to the key and the value." self key: nil value: nil Then I run it, and when I get into the mourn method, the key of the WeakKeyAssociation is still filled in. Isnt that strange? Because now I can still create references to the #key even though the WeakKeyAssociation (or an Ephemeron) thinks it was the only one having a reference to it. An EphemeronDictionary for instance removes the key from itself when an Ephemeron gets the #mourn method, but I would think that if during the process of the #mourn method another process would become active, it could create references to the key causing the EphemeronDictionary to still remove it, even though it shouldn't have causing all kinds of problems. Am I seeing this correct? Is this to be expected from ephemerons/EphemeronDictionary? Isn't that a dangerous property? Mark _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc --
Alan Knight [|], Engineering Manager, Cincom Smalltalk
_______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
I was thinking along the lines of perhaps using an EphemeronDictionary
to close external resources (like database cursors for instance). It would be simpler
to write the finalization code on the cursor itself, avoiding the shallowCopy
that is usually being used. But if I would for some reason use #associationsDo:
to collect them and do something with all the cursors in the dictionary, then
it could happen that they get closed while I'm running over them. It could be a
matter of not using methods like this, but to be on the safe side, the WeakDictionary
approach with shallowCopies may in this case be better suited. Thanks, Mark From: [hidden email]
[mailto:[hidden email]] On Behalf Of Alan Knight I don't think it's reasonable to say that #mourn is not
supposed to go and create new references. It's probably not a great idea, but
it's the sort of thing that might happen very easily. For example, simply
writing mourn as Content-class: urn:content-classes:message From: [hidden email]
[[hidden email]]
On Behalf Of Mark Plas -- Alan Knight [|], Engineering Manager, Cincom Smalltalk _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Alan Knight-2
Sure, but being stopped in the debugger is not the usual mode of
operation for #mourn either. Alan Knight wrote: > I don't think it's reasonable to say that #mourn is not supposed to go > and create new references. It's probably not a great idea, but it's > the sort of thing that might happen very easily. For example, simply > writing mourn as > self methodThatIForgotToActuallyImplement. > will bring up a debugger, and cause all kinds of strong references. > > In general, with things that are finalized by ephemerons, the policy > should be to write the finalization methods such that it is safe to > call them more than once. If we run arbitrary user code once those > objects are queued for garbage collection, that user code may end up, > intentionally or otherwise, causing the objects not to be garbage > collected. And then, presumably, at some later point, they will be. > This is a slight burden on the author of the code, but not that > difficult, and usually amounts to nil checks. > > The advantage of this approach is that you actually get to write the > finalization code on the object being finalized. The pre-ephemeron > finalization code did not have this property. You got notified only > _after_ the object was garbage collected. That was in some sense a > nice property, but one downside was that for finalization you had to > register some other object in a dictionary somewhere to get the > notification. In practice, some other object usually meant a shallow > copy of the object being finalized, and the registration and > management of that was also a burden. > > At 04:31 AM 7/9/2009, Valloud, Andres wrote: >> Content-class: urn:content-classes:message >> Content-Type: multipart/alternative; >> boundary="----_=_NextPart_001_01CA006F.A1F0EF7E" >> >> At the point when #mourn is queued to be sent, there are no other >> references to the key. The method for #mourn is not supposed to go >> ahead and create new references. Also, there should be no attempts to >> grabbing the keys of ephemerons for the reasons you describe. You may >> want to read the original ephemerons paper for the rationale behind >> their existence. >> >> ------------------------------------------------------------------------ >> *From:* [hidden email] [ mailto:[hidden email]] >> *On Behalf Of *Mark Plas >> *Sent:* Thursday, July 09, 2009 1:20 AM >> *To:* [hidden email] >> *Subject:* [vwnc] Question about Ephemerons >> >> Hello, >> >> >> >> There's something I don't understand about ephemerons. >> >> >> >> This is an experiment I did: >> >> >> >> | assoc | >> >> assoc := WeakKeyAssociation >> >> key: Object new >> >> value: 'something'. >> >> ObjectMemory globalGarbageCollect. >> >> >> >> >> >> >> >> Before I run this, I put a break point in the #mourn method on >> WeakKeyAssociation. >> >> >> >> mourn >> >> <BREAK POINT> >> >> "On mourning simply remove the reference to the key and the value." >> >> self key: nil value: nil >> >> >> >> Then I run it, and when I get into the mourn method, the key of the >> WeakKeyAssociation is still filled in. >> >> >> >> Isn’t that strange? Because now I can still create references to the >> #key even though the WeakKeyAssociation (or an Ephemeron) thinks it >> was the only one having a reference to it. An EphemeronDictionary for >> instance removes the key from itself when an Ephemeron gets the >> #mourn method, but I would think that if during the process of the >> #mourn method another process would become active, it could create >> references to the key causing the EphemeronDictionary to still remove >> it, even though it shouldn't have causing all kinds of problems. >> >> >> >> Am I seeing this correct? Is this to be expected from >> ephemerons/EphemeronDictionary? Isn't that a dangerous property? >> >> >> >> Mark >> _______________________________________________ >> vwnc mailing list >> [hidden email] >> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > -- > Alan Knight [|], Engineering Manager, Cincom Smalltalk > [hidden email] > [hidden email] > http://www.cincom.com/smalltalk vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |