Red Gate Software LTD toll free: 1 866 RED GATE Newnham House t: +44 (0)870 160 0037 Cambridge Business Park f: +44 (0)870 063 5117 Cambridge e: [email protected]CB4 0WZ www.red-gate.com RICKY LEEKS PRESENTS THE TOP 5 WPF AND SILVERLIGHT GOTCHAS With Chris Farrell INTRODUCTION As I’m sure you know, WPF and Silverlight both use XAML as their interface markup language. The idea is that you can define your user interface (UI) and bind it to data without ever writing a line of code (healthy skepticism advised). Whether or not you buy into that vision, the UI possibilities can be stunning, and it seems Microsoft has created a technology that combines both power and flexibility. However, with that power comes responsibility. It’s with an eye on that responsibility that I write this article, in which I want to talk about some of the problems you can i ntroduce into your application without even realizing it. BACKGROUND .NET uses a garbage collector to reclaim and reuse the space left behind when objects are no longer needed. To do this, it builds a list of all objects that are still ultimately referenced from an application root such as the stack, other objects on the heap, the CPU and statics, to name just a few. Everything else (i.e. objects which have no such references) is assumed to be garbage, and .NET rearranges memory allocation to reuse the gaps these objects filled. A leak(or, if you’re being picky, leak-like behavior) occurs when a section of code fails to release references to objects it has finished working with. The smaller the leak, the greater the number ofiterations that must occur before it becomes a noticeable problem. The larger the leak, the more obvious the problem. A really obvious example of this problem is adding an object to a static collection and then forgetting about it. Other common ones involve event handling, which we will d iscuss later. The simple fact is that if you leave a reference to a n object behind and that reference traces back to an application root, then you have a leak. There are lots of great articles about.NET memory management, and one of the first things you can do to avoid leaks in general is to really understand memory management.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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 such as images and media. All of this “stuff” adds tothe size of the views we create and, ultimately, the size of a memory leak when things go wrong.
If you have a memory leak that involves a complex UI then it can quickly become a major
problem, especially if users are constantly opening and closing windows as part of standard
flows.
This is exactly the situation I found with a large financial application written in WPF, employing
all the usual accounting/finance type windows, often containing many hundreds of rows of data.
As you would expect, the developers had taken full advantage of data binding and the entity
framework. It looked great and all seemed well until, during system testing, they discovered that
the application would get slower over time and ultimately crash the machine. Eventually they
actually had to reboot to get over it. Naturally I suspected a memory leak, but nothing could
prepare me for the extent of the issues I actually found.
Some of the issues were specific to WPF/XAML and Silverlight, and others were general leaks you
will get in any application. I thought it would be useful to go through the main technology-
specific leaks you can easily create; the good thing is that they are easy to fix and avoid in the
future.
WPF AND SILVERLIGHT LEAKS
While I‘ve tried to come up with a list of the most likely leaks, the trouble is that, depending on
platform and framework versions, there are many potential leak mistakes you can make.
Regardless, you’ve got to start somewhere, and these points will always serve you well. You’relikely to quickly see a pattern emerging in the underlying nature of the problems and solutions I
highlight, but I do recommend you read to the end, because I almost guarantee that you’llencounter one of these situations sooner or later.
UNREGISTERED EVENTS (WPF + SILVERLIGHT, ALL VERSIONS)
Let’s start with the classic leak common to all .NET applications - the event leak. While this is a
common source of leaks for all .NET applications, it’s not a bug in .NET, but rather a common
oversight by developers.
Specifically, if you add an event handler to handle events occurring in another object, then if you
don’t clear the link when you have finished, an unwanted strong reference will be left behind.
My contrived example below deliberately isn’t specific to WPF/Silverlight , but I include it
because it’s a very common memory leak which all .NET applications are vulnerable to. In it I amsubscribing to an OnPlaced event on my Order class. Imagine this code executes on a button
click. Basically, it sets up an order for a currency exchange to take place when certain price
conditions are met:
Order newOrder=new Order(“EURUSD”, DealType.Buy, Price ,PriceTolerance, TakeProfit, StopLoss);
newOrder.OnPlaced+=OrderPlaced;
m_PendingDeals.Add(newOrder);
Listing 1
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);
}
Listing 2
In the event handler, you can see that we are eliminating a really common source of leaks;
namely, references from collections (in this case the m_PendingDeals collection).
However, 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.
THE SOLUTION
The OrderPlaced method is just one line away from avoiding a memory leak!
void OrderPlaced(Order placedOrder)
{
m_PendingDeals.Remove(placedOrder);
m_Currency.OnPriceUpdate -= placedOrder.OnTick;
}
Listing 3
The last line unsubscribes the event and removes the strong reference. If this is news to you, then
drop everything and look at all your event handling code. Chances are you have a leak.
You read that right; data binding, the thing you rely on, can cause memory leaks. Strictly speakingit’s actually the way you use it that causes the leak , and once you know about it it’s easy to either
avoid or code around this issue.
THE ISSUE
If you have a child object that data binds to a property of its parent, a memory leak can occur. An
You may be able to see what the problem is just from reading the code above because, at the
moment, it leaks. It’s because we are leaving a strong reference in the
mainWindow.main.CommandBindings object pointing to the child. As a result, event when thechild closes, it will still remain in memory due to the held reference.
This is obviously a contrived example to illustrate the point, but you can easily set this scenario
up without even realizing it.
THE SOLUTION
Again, the solution couldn’t be easier and, not surprisingly, involves removing the command
The last leak I want to draw your attention to is not really a leak; it is intended behavior, but it’simportant to know it’s there.
THE PROBLEM
The problem is to do with the TextBox control and UNDO. TextBoxes have built-in undo
functionality, enabling a user to undo their changes to a text box. 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 memoryprofile traces and there is no point being distracted by it.
THE SOLUTION
You can limit the behavior of the undo stack by either switching it off using:
textBox1.IsUndoEnabled=false;
Listing 13
Or alternatively you can reduce it’s impact by setting the UndoLimit property:
textBox1.UndoLimit=100;
Listing 14
This limits the number of actions that can be undone, in this case to 100; By default the setting is
-1 which limits the number of actions only by the amount of memory available. Setting the value