Ricky Leeks presents:

Memory leaks to watch out for in WPF and Silverlight

Memory leaks to watch out for in WPF and Silverlight

WPF and Silverlight allow you to define your user interface and bind it to data with a minimum of code, meaning that you can also introduce memory leaks into your application without even realizing it. And because Silverlight and WPF applications are state-full, and allow us to hold state in the form of complex data structures as well as rich UI elements, this can add to the size of memory leaks when things go wrong.

Pitfall 1

Unregistered events

A classic leak common to all .NET applications, and a common oversight by developers. If you create an event handler to handle events occurring in some other object then, if you don't clear the link when you've finished, an unwanted strong reference will be left behind.

Say I am subscribing to an OnPlaced event on my Order class, and say this code executes on a button click:

Order newOrder=new Order
(“EURUSD”, DealType.Buy, Price ,PriceTolerance, TakeProfit, StopLoss);

newOrder.OnPlaced+=OrderPlaced;
m_PendingDeals.Add(newOrder);

When the price is right, an Order completes and calls the OnPlaced event, which is handled by the OrderPlaced method:

void OrderPlace(Order placedOrder)
{
	m_PendingDeals.Remove(placedOrder);
}

The OrderPlaced event handler still holds a reference to the Order object from when we subscribed to the OnPlaced event, and that reference will keep the Order object alive even though we have removed it from the collection. It's so easy to make this mistake.

Pitfall 2

Databinding

You read that right; data binding, the thing you rely on, can cause memory leaks. Strictly speaking it's actually the way you use it that causes the leak. If you have a child object that data binds to a property of its parent, a memory leak can occur. An example of this is shown below.

<Grid Name="mainGrid">

    <TextBlock Name=”txtMainText”
    Text="{Binding ElementName=mainGrid, Path=Children.Count}" />

</Grid>

The condition will only occur if the bound property is a PropertyDescriptor property, as Children.Count is. This is because, in order to detect when a PropertyDescriptor property changes, the framework has to subscribe to the ValueChanged event, which in turn sets up a strong reference chain.

Pitfall 3

Static events

Subscribing to an event on a static object will set up a strong reference to any objects handling that event. Statics, one referenced, remain for the duration of the app domain execution, and therefore so do all their references. And strong references preventing garbage collection are just memory leaks by another name.

Pitfall 4

Command binding

Command binding allows you to separate common application commands (and their invocation) from where they are handled. You can write your classes to handle specific commands, or not, and even indicate if those commands can be executed. The problem, much like the others we've seen, occurs when these bindings leave unwanted strong references lying around.

Say I'm setting up some code within a child window to handle when Cut is executed within the parent mainWindow. I first create a CommandBinding, and then simply add it to the parent windows CommandBindings collection:

The good news is that the .NET framework now takes care of freeing objects for you, and is also ultra-cautious. It works out whether it thinks a particular object is going to be needed while your program runs, and it will only release that object if it can completely guarantee that that object is not going to be needed again.

	CommandBinding cutCmdBinding = new CommandBinding
	(ApplicationCommands.Cut, OnMyCutHandler, OnCanICut);

	 mainWindow.main.CommandBindings.Add(cutCmdBinding);

	...
	void OnMyCutHandler (object target, ExecutedRoutedEventArgs e)
	{

	    MessageBox.Show("You attempted to CUT");
	}

	void OnCanICut (object sender, CanExecuteRoutedEventArgs e)
	{
	    e.CanExecute = true;
	}
	

This code leaks because we are leaving a strong reference in the mainWindow.main.CommandBindings object pointing to the child. As a result, even when the child closes, it will still remain in memory.

Pitfall 5

Dispatchertimer leak

Improper use of the DispatcherTimer will cause a memory leak. The code below creates a new DispatcherTimer within a user control, and to make it easier to see the leak, I have also added a byte array called myMemory to make the leak more obvious.


	public byte[] myMemory = new byte[50 * 1024 * 1024];

	System.Windows.Threading.DispatcherTimer _timer = new System.Windows
	.Threading.DispatcherTimer();
	int count = 0;

	private void MyLabel_Loaded(object sender, RoutedEventArgs e)
	{

		_timer.Interval = TimeSpan.FromMilliseconds(1000);

		_timer.Tick += new EventHandler(delegate(object s, EventArgs ev)

		{
			count++;
			textBox1.Text = count.ToString();
			});

		_timer.Start();
	}
	

On my main window I am adding an instance of the UserControl to a StackPanel (after removing children first) on a button click, which will leak memory with every click. Tracing it backwards using ANTS Memory Profiler shows that the UserControl as the source of the leak.

The problem is, once again, a reference being held, this time by the Dispatcher, which holds a collection of live DispatcherTimers. The strong reference from the collection keeps each UserControl alive, and therefore leaks memory.

Bonus Pitfall

Textbox undo leak

This is not really a leak; it is intended behavior, but it's important to know it's there. TextBoxes have built-in undo functionality, enabling a user to undo their changes to a text box. To allow for that, WPF maintains a stack of recent changes, and when you use a memory profiler you can clearly see a build up of data on this undo stack. This isn't a major problem unless your app is updating large strings to text boxes over many iterations. The main reason to note this behavior is because it can often show up on memory profile traces and there is no point being distracted by it.