From: Ryan Pavlik Date: 2003-08-09T10:42:55+09:00 Subject: Re: WeakRef and caches On Sat, 9 Aug 2003 10:22:13 +0900 Tim Bates wrote: > Hi all, > I'm trying to build a caching mechanism into a library I'm writing. I > want to do it using weakrefs. It will look something like this: > Funny, I was just working on this. ;-) > It seems, though, that the WeakRef implementation is such that if you > refer to an object other than via its weakref, the weakref-ness is > destroyed and the object never gets GC'd. Can anyone explain why and/or > offer a way around this? Here's what I did. The idea was that the system would be addressing an indeterminate number of persistant objects, in a transparent (to the user/developer) manner. Thus, the problem was twofold: * We need one unique reference for each object, so reloading objects from the object store doesn't create copies and we have sync problems * Reading from the disk all the time is slow Keeping everything in memory is also out, since the system needs to scale. This gives you an idea what the cache was _for_. To accomplish this, I keep _two_ caches: a "strong" cache and a "weak" cache. The "strong" holds objects until it's determined that they've expired---the strong cache limit is reached, and they're written to disk and removed from the strong cache. When an object is referred to, first I check the strong cache, then I check the weak cache. If it's found in the strong cache, I return it normally. If it's in the weak cache, I put it in the strong cache, and return it. (This solves the multiple-references problem.) If it's not found in either, load it from disk and put it in both. The garbage collector does its stuff to keep things within limits. Unfortunately this isn't perfect---I'd like to expire stuff from the cache based on size, so I could set a memory limit, but Ruby has no way for querying object size (*). Also, there's some further evil magic required to make sure things get written to the disk as appropriate. (For instance, if an object which has a reference changes the object after it's expired from the strong cache, it needs written again.) Not having destructors makes this slightly painful, and finalizers don't work here. Depending on what you're doing, this scheme ought to work---I'm not sure how you're adding and removing objects, but it's probably similar if you're wanting to cache them---just make sure you've got all the cases covered. ;) (If you need a fully-functional transparently persistant object system with this sort of thing already implemented, lemme know, I can give you the code.) hth, -- Ryan Pavlik "The fact that you believe in something called a 'Babedar' *alone* leads me to conclude that it's always wrong." - 8BT