Table of Contents
When working in C#, most of the time we access objects through so-called strong references. With strong references, if the application code can still reach a certain object, then it cannot be garbage collected and, if that object is then referencing other objects, then those also cannot be collected themselves.
Weak references, instead, allow the garbage collector to freely collect objects at will to free memory space, while still allowing to access them before they get collected. Weak references are particularly useful when we need to reference objects that can potentially use a lot of memory, but can be recreated easily. Weak references can also be useful to avoid creating strong circular references that can prevent objects from being collected, for instance in iOS.
In this small blog post I’ll go over how to create and use a weak reference, and also how to test that it gets correctly garbage collected. If you need more information about weak references themselves, then you can take a look at the documentation.
How to create and use a weak reference #
In C# you can use the
WeakReference class to create a weak reference to an object.
For example, let’s imagine that we have a
Container class with a
MainView could potentially occupy quite a lot of memory, but it’s relatively easy to re-create. For this reason we prefer to keep it as a weak reference:
public class Container
private WeakReference<View>? mainViewWeakReference;
public View MainView
if (mainViewWeakReference is null || !mainViewWeakReference.TryGetTarget(out var targetView))
// Possibly View could occupy a lot of memory
targetView = new View();
if (mainViewWeakReference is null)
mainViewWeakReference = new WeakReference<View>(targetView);
MainView property here is used to return the contained main view, as an example.
There are a couple of things to notice:
- We use
TryGetTargetto check if the contained
Viewhas been collected already. If it has not been collected, then we just return it.
- Otherwise we create the
Viewobject, and then we either create the
WeakReference<View>object, or we change the target object contained in
After the getter is called, the GC is free to collect the contained view when there are not other strong references to it.
Another small thing to notice is that we actually have a strong reference to
WeakReference in the code, but the
View object inside it is stored as a weak reference.
How to test a weak reference #
Writing a unit test to verify if the target of a weak reference is garbage collected correctly is a little bit tricky, because in order for that to happen there shouldn’t be any strong reference to it. For this reason, the easiest way to create a unit test is to make a weak reference to the object that we expect to be collected in a delegate or another method, for example in an
Func, like in the following example:
public void VerifyThatViewIsGarbageCollected()
var container = new Container();
var wr = new Func<WeakReference>(() =>
return new WeakReference(container.MainView);
This test is verifying that
Container.MainView is garbage collected. To do so, we create a weak reference to it in the
Func, and then return it. We then force garbage collection by calling
GC.Collect, and then we verify that the target has been garbage collected with
IsAlive. In this case we are creating the weak reference inside the
Func delegate, so that after the delegate is called, there will be no actual strong reference to
MainView, so that we can verify it gets actually collected.
As a final note, please remember that the way that garbage collection works is slightly different ways when working in Debug or Release mode, so that’s something to take into considerations when testing.