From: Bob Alexander Date: 2002-03-13T00:39:51+09:00 Subject: Thoughts on WeakRefs and ObjectSpace This is a multi-part message in MIME format. ------=_NextPart_000_005C_01C1C999.5667FF80 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable I've recently been working on a project that needs weak references, and = I've noticed a few things I'd like to discuss with "the list". First of all, glancing at the "weakref.rb" code, it seems that nothing = ever gets deleted from the hashes ID_MAP and ID_REV_MAP. It looks to me = like a memory leak. Instead of just assigning nil to no-longer-needed = entries, they should be deleted. Secondly, it's often necessary to "neutralize" a finalizer that has been = installed. An example is implementing a "weak value hash". When a value = is assigned to the hash, a finalizer is installed in the value to delete = its entry from the hash. If that value's weak reference is removed from = the hash (either deleted or assigned over), the finalizer should be = "neutralized" since it is no longer appropriate to delete its foprmer = key from the hash. It's possible (but inconvenient) to do this in Ruby = by messing with the environment captured by the finalizer, but the = "right" thing to do is to discard the finalizer. Currently the only = option is to remove *all* finalizers from the object, not individual = ones, but that is dangerous because the object might have other = finalizers installed for other reasons. The only current choice is to = neutralize but not remove the finalizer. An object could end up with = lots of unnecessary finalizers. A possible solution for the above is that ObjectSpace::define_finalizer = could return a "finalizer ID". Then ObjectSpace::undefine_finalizer = could take the ID as an argument and remove only that finalizer. Then a = weak value hash could undefine its finalizer (and only its finalizer) if = the value is removed. I noticed that currently ObjectSpace::define_finalizer returns the proc = installed, but that might not a good ID since the same proc could be = used for several finalizers (as is currently done in the WeakRef = module). Here's another thought: A frequent need (a pattern) is to have a weak = reference with an associated finalization action on its referent that = must be cancelled at some point (such as in the weak value hash example = above). Maybe WeakRef::new could take a second, optional argument, a = finalizer proc for its object. Then calling something like = WeakRef#cancel_finalizer could conveniently cancel that action. = WeakRef#cancel_finalizer would automatically be called when the WeakRef = itself is finalized. This is a "convenience" facility, since it is = possible to accomplish this in other ways. I've implemented my own experimental WeakRef that does what I've = suggested (although I didn't implement the ObjectSpace ideas, which = would be helpful). I'm also trying to implement a weak value hash, which = is what brought some the these perceived shortcomings to my attention. = By the way, since weak value hashes and weak key hashes are often needed = and nontrivial to implement, they would be nice additions to the Ruby = library (both Python and Java have them). Just some random thoughts... Bob ------=_NextPart_000_005C_01C1C999.5667FF80 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable
I've recently been working on a project = that needs weak references, and I've noticed a few things I'd like = to=20 discuss with "the list".
 
First of all, glancing at the = "weakref.rb" code, it=20 seems that nothing ever gets deleted from the hashes ID_MAP and = ID_REV_MAP. It=20 looks to me like a memory leak. Instead of just assigning nil to=20 no-longer-needed entries, they should be deleted.
 
Secondly, it's often necessary to = "neutralize" a=20 finalizer that has been installed. An example is implementing a "weak = value=20 hash". When a value is assigned to the hash, a finalizer is installed in = the=20 value to delete its entry from the hash. If that value's weak = reference is=20 removed from the hash (either deleted or assigned over), the finalizer = should be=20 "neutralized" since it is no longer appropriate to delete its foprmer = key from=20 the hash. It's possible (but inconvenient) to do this in Ruby by messing = with=20 the environment captured by the finalizer, but the "right" thing to do = is to=20 discard the finalizer. Currently the only option is to remove *all* = finalizers=20 from the object, not individual ones, but that is dangerous because the = object=20 might have other finalizers installed for other reasons. The only = current choice=20 is to neutralize but not remove the finalizer. An object could end up = with lots=20 of unnecessary finalizers.
 
A possible solution for the above is = that=20 ObjectSpace::define_finalizer could return a "finalizer ID". Then=20 ObjectSpace::undefine_finalizer could take the ID as an argument and = remove only=20 that finalizer. Then a weak value hash could undefine its finalizer (and = only=20 its finalizer) if the value is removed.
 
I noticed that currently=20 ObjectSpace::define_finalizer returns the proc installed, but = that might=20 not a good ID since the same proc could be used for several = finalizers (as=20 is currently done in the WeakRef module).
 
Here's another thought: A frequent = need (a=20 pattern) is to have a weak reference with an associated finalization = action on=20 its referent that must be cancelled at some point (such as in the weak = value=20 hash example above). Maybe WeakRef::new could take a second, optional = argument,=20 a finalizer proc for its object. Then calling something like=20 WeakRef#cancel_finalizer could conveniently cancel that action.=20 WeakRef#cancel_finalizer would automatically be called when the WeakRef = itself=20 is finalized. This is a "convenience" facility, since it is possible to=20 accomplish this in other ways.
 
I've implemented my own experimental = WeakRef that=20 does what I've suggested (although I didn't implement the ObjectSpace = ideas,=20 which would be helpful). I'm also trying to implement a weak value hash, = which is what brought some the these perceived shortcomings to = my=20 attention. By the way, since weak value hashes and weak key hashes are = often=20 needed and nontrivial to implement, they would be nice additions to the = Ruby=20 library (both Python and Java have them).
 
Just some random = thoughts...
 
 
Bob
------=_NextPart_000_005C_01C1C999.5667FF80--