System.WeakReference: Solution in Search of a Problem
.NET has a WeakReference class, whose semantics appear to have been borrowed from Java. As nearly as I can tell, they're both useless.
A WeakReference is an object that holds a reference to another object. However, it holds a special type of reference, that doesn't prevent the target from being reclaimed by the garbage collector. At first blush, this seems perfect for implementing a cache -- as long as the system doesn't need the memory, we've got the object; should the system need the memory, the object goes away and we transparently re-create it next time we need it. Unfortunately, this doesn't quite work.
First, a cache is only interesting to create in the first place if two things are true:
- The objects are big enough that we can't keep them in memory indefinitely, and
- They're sufficiently expensive to create that we can't re-create them every time we need them.
We probably implement our cache using some sort of a dictionary or hash table that maps from the object identity to the cached value. In C# terms, a Dictionary<string,WeakReference>. Now, when a garbage collection occurs, the target object goes away, but the entries in the dictionary remain. Over time, we'll end up with lots and lots of entries in the dictionary, each holding a WeakReference whose target is gone. This leads to the next constraint:
- Caching using a dictionary of WeakReference's is useful only when the total population of the data subject to caching is small.
Otherwise, the dictionary will explode with useless entries.
The next problem is that not only does a WeakReference not prevent an object from being garbage-collected, it doesn't even suggest that the object shouldn't be. So the next time a garbage collection comes around, all of your otherwise-unreferenced objects are reclaimed. So your cache doesn't really hold objects until the memory is needed; it only holds objects until the next garbage-collection. This implies:
- Caching using WeakReference's isn't appropriate unless the objects are cheap enough to be thrown away (and later re-created) on every garbage collection.
I would assert that the set of problems that meet all of the above criteria is empty. After all, we just said:
- The objects are big,
- They're expensive to create,
- There aren't very many of them, and
- They're cheap to create.
Now, it's possible to get around the "not many of them" restriction with some very ugly code involving finalizers that remove entries from the hash table. (I doubt that it would be performant, but it is possible.) But I don't see how you can possibly reconcile "expensive to create" and "cheap to create".
So, has anyone out there ever successfully used Weak Reference's? If you used it for a cache, do you have measurements of how much it helped performance? If you used it for something else, what was it?