Taco Steemers

A personal blog.
☼ / ☾

Weak references, are you sure you want to use them?

One of the projects that I have been working on lately is a standard C# codebase, a framework of sorts, for a particular niche category of software.  This is for a client that develops and uses a lot of this kind of applications in-house. Many of these have been written as a stand-alone effort. Some are difficult to maintain and extend, as each development effort followed it's own path.

I have looked at the MVVM Light Toolkit to see if it could be of use to us. My test application would show odd behaviour. After a little while, an exception would show up when I clicked a button. The root cause is a series of null-checks in the toolkit, that don't cover all cases. Also of interest to me was how my code led to that bug showing up.

I found that the target of a reference that I had passed to a MVVM Light Messenger object had become garbage collected. A Messenger object can be used for communication between viewmodels. Internally, the Messenger object held a weak reference to the object I had passed in. In my test application, that object went out of scope almost immediately. Because there only existed a weak reference to it, the garbage collecter removed it. Subsequently, the Messenger object's weak reference no longer had a target, i.e., it pointed to an object that did not exist anymore.

I had thought that the Messenger's reference to my object would keep my object from being gc'ed, but because some of the Messenger's internal references are a WeakReference, it does not stop those objects from becoming eligible for garbage collection.

As it turns out, this has been listed as a bug on the MVVM Light Toolkit's CodePlex repository .

This is a simple example of how one might encounter this situation (copied from a post on that same page): ``

public MainWindow()
{
    InitializeComponent();

    LogManager _log = new LogManager(typeof(MainWindow).Name);

    Messenger.Default.Register<NotificationMessage>(this,
    x =>
    {
         // call to this fails on .Send unless you remove the local _log reference
         // or change the local variable to being a field of the 
         //  MainWindow class instead was a simple workaround for me
        _log.Error("An unexpected error occured. " + x.Notification, x.Content);
    });
 }

If I recall correctly, my case was different. I passed the object as the first variable, the recipient.

I'm not certain that this should be classified as a bug in the MVVM Light Toolkit, as this is probably by design. It makes sense to use weak references for event-related things because one might forget to unsubscribe ones objects, a situation which I would consider a memory leak. Then again, why would you want that for the Messenger object, typically used by viewmodels which exist during the entire lifetime of an application?

I'm not making use of the MVVM light framework anymore, but because initially it looked as though I would, I had to do something with this situation. I can't give my coworkers a codebase that makes it that easy to create bugs that are easy to miss. A bug like this is easy to miss during testing because it occurs intermittently. Many developers have a fuzzy understanding of how memory management works (in general, or in whatever language or runtime they end up using today or tomorrow), which could make this kind of situation difficult to fix.

I set out to find a way to be able to use the MVVM Light Toolkit code to keep the relevant objects alive longer, and settled on using a ConditionalWeakTable . The way the adjusted Messenger makes use of it ensures that the targets of the weak references do not get gc'ed, but the entry itself will be removed and gc'ed when it is no longer relevant to the Messenger. This means that the rest of the code does not need changing. Unfortunately, this type of collection is only available starting from C# 4.0.

I haven't proposed a patch to the Toolkit's codebase. In this instance, my own preference simply appears to be different than those of the Toolkit's author. The Toolkit isn't meant to help develop intense event-based systems, it is intended for user-facing systems with a GUI. If you are not writing real-time systems, are you sure you need to use a weak reference?