Many say that weak references are not a good choice for a caching mechanism, but I disagree. In my opinion, weak references are incomplete for a caching mechanism as, if you only have weak references to your cached objects, they will die at every collection. So, to solve this problem, the simplest option is to create a
KeepAlive feature that guarantees that recently used objects will not be collected, and then use the weak references, as they will allow you to use your object better, as a simple "timed cache" may reload data that is still in memory.
I created my first caching solution to solve the problem of sending large viewstates to clients and to avoid storing large information in sessions. The idea was simple. When a
Cache<T> object was created, it serialized its target object in a temporary directory. The cleanup of such a directory or how I did it to be fast is not the case. When I didn't have the information in memory, I loaded it from the serialized data. When I had it in memory, I simply reused it. But, after a collection, I needed to reload all the cached objects that were actively used. So, I implemented the first version of the
GCUtils class, with a method named
KeepAlive that allowed an object to live for 30 seconds after its last use, thus surviving collections during this time. Now, I use a much better version that allows the object to survive only to the next collection. After that, if a new
KeepAlive is not done, the second collection will collect it.
Using the Code
I have uploaded a zip file with this article with the source code of a DLL of my own, and a sample that shows how to use
WeakKeyDictionary. The DLL also has some other useful classes, but for this article, these three classes are the most important ones.
GCUtils has two important items. The first is the
Collected event. I use this method in my
WeakKeyDictionary to remove collected references. Also, if you see my implementation, I have used the
WeakKeyDictionary, but that's because the
GCHandle is the class that really does the weak reference work, but it is "unsafe" to use as it can leak memory if used improperly.
Collected event is very useful. For example, you can add a handler to the
Collected event to do a
TrimExcess in your lists or hashsets. After all, a weak reference will not allow you to free memory by doing a
Collected works in another thread, so the collected handler must be thread safe. For example, in the class constructor, you call:
GCUtils.Collected += p_Collected;
And then, you implement
private void p_Collected()
GCUtils.Collected += p_Collected;
var oldDictionary = fDictionary;
var newDictionary = new Dictionary<TKey, ExtendedGCHandle>();
foreach(var pair in oldDictionary)
var wr = pair.Value;
fDictionary = newDictionary;
This is the code used by
WeakDictionary to remove unused items. I must re-register for the
Collected event, as the collected list is cleared when it runs. The really important part here is to see the use of the
lock keyword, as the entire class must access its dictionary using a lock.
And, the other important item of
GCUtils is the
KeepAlive method. The
GC.KeepAlive is not the same.
GC.KeepAlive keeps an object alive until that specific line of code.
GCUtils.KeepAlive keeps an object alive for the next collection.
The other interesting classes are
KeepAliveWeakReference is a
WeakReference inheritor that simple calls
KeepAlive every time its target is got. So, you can use only such
WeakReference as the reference to the item you want to cache (for example, the background image used in the example of how to use
WeakReferences in the MSDN help), and you guarantee that it will not be collected while you are constantly re-rendering the background, even if a collection happens. And, if it stops being used, then it will die after the second collection.
For example, declare a variable like:
var weakReference = new KeepAliveWeakReference<byte>(bytes);
bytes can be an array of many MB. And then, you access it like:
byte bytes = weakReference.Target;
Doing this already calls
KeepAlive for you. So, if bytes is not
null, you can use it safely.
WeakDictionary is effectively a dictionary where values can be collected. It does not use
WeakReferences, using the
GCHandle directly for performance, but the idea is the same. And, in the
Collected event, it removes the values that becomes
WeakKeyDictionary allows the keys to be collected. This is useful if you want to "add" fields to existing classes. For example, using extension methods, I add the
SetTag (simulating the
Tag property that I used in Delphi) to any object. But, if I use a dictionary to do this, I will not allow an object with a tag to be collected. Using
WeakKeyDictionary, I allow this.
Here is the source code. I simply use a
WeakKeyDictionary to store the tag value. I consider the default value to be
-1, so if the object does not have a tag,
-1 is returned, and setting
-1 to the tag value will remove it from the dictionary. The way the dictionary works, while the object is alive, its tag is alive. Just after it dies, the tag in the dictionary dies too.
public static class PropertyExtender
private static WeakKeyDictionary<object, int> fTags =
public static int GetTag(this object obj)
if (fTags.TryGetValue(obj, out result))
public static void SetTag(this object obj, int tagValue)
if (tagValue == -1)
fTags[obj] = tagValue;
- 7th April, 2009: Initial post
- 8th April, 2009: New version of the library and sample