Top Banner
 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 of iterations 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.
10

WPF Silver Light Pitfalls

Apr 06, 2018

Download

Documents

hansemohr
Welcome message from author
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.
Transcript
Page 1: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 1/9

 

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 GOTCHASWith 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 introduce 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 of 

iterations that must occur before it becomes a noticeable problem. The larger the leak, the moreobvious 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 discuss later. The

simple fact is that if you leave a reference to an 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.

Page 2: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 2/9

 

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

HEAVYWEIGHT USER INTERFACES IN XAML

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.

Page 3: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 3/9

 

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

THE ISSUE

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.

Page 4: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 4/9

 

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

DATABINDING (WPF + SILVERLIGHT, ALL VERSIONS)

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

example of this is shown in Listing 4. 

<Grid Name="mainGrid"> 

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

</Grid> 

Listing 4: DataBinding Leak Example

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.

If the binding is marked as OneTime, the bound property is a DependencyProperty, or the

object implements INotifyPropertyChanged, then the issue won’t occur. In the case of OneTime 

binding this is because, as the name suggests, it doesn’t need to detect property changes, with the

binding occurring once from data source to consumer.

SOLUTION

There are a number of work-arounds for this problem.

1.  Add a DependencyProperty to the page/window which simply returns the value of the

required PropertyDescriptor property. Binding to this property instead will get solve

the problem..

2.  Make the binding OneTime 

Text="{Binding Path=Salary, Mode=OneTime}"/ Listing 5

3.  Add the following line of code on exit from the page:

BindingOperations.ClearBinding(txtMainText, TextBlock .TextProperty);

This simply clears the binding and removes the reference.

Listing 6

Page 5: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 5/9

 

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

STATIC EVENTS (WPF + SILVERLIGHT, ALL VERSIONS)

Subscribing to an event on a static object will set up a strong reference to any objects handling

that event. Statics are a classic source of root references, and are responsible for a high

proportion of leaks in code.

Statics, once referenced, remain for the duration of the app domain execution, and therefore so

do all their references. Strong references preventing garbage collection are just memory leaks by

another name.

To show you what I mean, the code below subscribes the calling class to the event source,

EventToLeak , on the static object MyStaticClass:

MyStaticClass.EventToLeak += new EventHandler(AnEvent);

Listing 7

The handling event, AnEvent , will be called when the EventToLeak event fires:

protected override void AnEvent(EventArgs e)

{

// Do Something

}

Listing 8

If you don’t subsequently unsubscribe the event, then it will leak because MyStaticClass 

continues to hold a strong reference to the calling class.

THE SOLUTION

To unsubscribe, simply add the code line

MyStaticClass.EventToLeak -= this.AnEvent;

Which releases the strong reference from MyStaticClass. It’s a simple solution, but then it’s a

simple problem – human error and oversight.

COMMAND BINDING

Command binding is a really useful feature in WPF; it allows you to separate common application

commands (such as Cut, Paste, etc )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. As useful as these bindings are, you do have to be careful about how you use them.

Page 6: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 6/9

 

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

THE ISSUE

In the following example I am 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.

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;} 

Listing 9

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

binding reference:

mainWindow.main.CommandBindings.Remove(cutCmdBinding);

Listing 10

Once this reference is removed, the leak will go away.

Page 7: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 7/9

 

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

DISPATCHERTIMER LEAK

Improper use of the DispatcherTimer will cause a memory leak. There’s not much more

background to this, so let’s just jump right in. 

THE PROBLEM

The code below creates a new DispatcherTimer within a user control. A textbox is updated with

the contents of the count variable, which is updated every second by the DispatcherTimer. To

make it easier to see the leak, I have also added a byte array called myMemory which just makes

the leak much bigger and easier to see.

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();

}

Listing 11

On my main window I am adding an instance of the UserControl to a StackPanel (after

removing children first) on a button click. This will leak memory for every button click, and in

this example the main leak you will see is the byte array. Tracing it backwards using ANTS

profiler show that the UserControl as the source of the leak.

This probably feels familiar, as 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.

THE SOLUTION

The solution is really simple but easy to forget and, you guessed it, you’ve got to stop the timer

and set it to null. Here’s the code to do that :

_timer.Stop();

_timer=null;

Listing 12

Page 8: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 8/9

 

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

TEXTBOX UNDO LEAK

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

to zero switches undo off.

Page 9: WPF Silver Light Pitfalls

8/3/2019 WPF Silver Light Pitfalls

http://slidepdf.com/reader/full/wpf-silver-light-pitfalls 9/9

 

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

CONCLUSION

None of this is rocket science, and it’s all based on the same principle which is “leave a reference

behind and potentially you have a leak ”. Obviously that depends on whether the left reference is

ultimately connected to a root reference.

While nothing I have covered is strictly speaking a bug, all of the points are definitely gotchas

that you can easily be caught by without realizing it. I should know, because I see them all again

and again in the projects that I work on.

Ultimately, the two things I recommend you do to avoid memory leaks in the future are:

  Learn all you can about .NET memory management and how your code impacts it 

  Get used to routinely using a memory profiler and interpreting it’s results