In Writing High-Performance .NET Code, I mention the WeakReference type briefly in Chapter 2 (Garbage Collection), but I don’t go into it too much. However, for the blog, I want to start a small series of posts going into some more detail about
WeakReference, how it works, and when to use it, with some example implementations. In this first post, I’ll just cover what it is, what options there are, and how to use it.
A WeakReference is a reference to an object, but one that still allows the garbage collector to destroy the object and reclaim its memory. This is in contrast to a strong (i.e., normal) reference that does prevent the GC from cleaning up the object.
There are two versions of
First, let’s take a look a
WeakReference, which has been around since .NET 1.1.
You allocate a weak reference like this:
var weakRef = new WeakReference(myObj);
myObj = null;
myObj is an existing object of your choice. Once you assign it to the
weakRef variable, you should set the original strong reference to null (otherwise, what’s the point?). Now, whenever there is a garbage collection the object
weakRef is referring to may be collected. To access this object, you may be tempted to make use
WeakReference’s IsAlive property, as in this example:
WeakReference ref1 = new WeakReference(new MyObject());
DoSomething(ref1.Target as MyObject);
IsAlive is a rather silly property. If it returns false, it’s fine–you know the object has been collected. However, if it returns true, then you don’t actually know anything useful because the object could still be garbage collected before you get a chance to make a strong reference to it!
The correct way to use this is to ignore the
IsAlive property completely and just attempt to make a strong reference from Target:
MyObject obj = ref1.Target as MyObject;
if (obj != null)
Now there is no race. If obj ends up being non-null, then you’ve got a strong reference that is guaranteed to not be garbage collected (until your own strong reference goes out of scope).
Recognizing some of the silliness and umm…weakness of
WeakReference<T> was introduced in .NET 4.5 and it formalizes the above procedure by removing both the
IsAlive properties from the class and providing you with these two methods:
- SetTarget – Set a new target object
- TryGetTarget – Attempt to retrieve the object and assign it to a strong reference
This example demonstrates the usage, which is essentially the same as the correct way to use
WeakReference from above:
WeakReference<MyObject> ref2 = new WeakReference<MyObject>(new MyObject());
if (ref2.TryGetTarget(out obj2))
You could also ask yourself: Why is there a
SetTarget method at all? After all, you could just allocate a new
If you are using
WeakReference<T> at all, it likely means you are somewhat memory conscious . In this case, allocating new
WeakReference<T> objects will contribute extra, unnecessary memory pressure, potentially worsening the overall performance. Why do this, when you can just reuse the
WeakReference<T> object for new targets as needed?
Next time, more details on weak references, particularly the differences between short and long weak references, and taking a peek at them in the debugger. We’ll also cover when you should actually use
WeakReference<T> at all.
Part 2, Short vs. Long Weak References and Object Resurrection, is up.
Part 3, Practical Uses, is up.