Recently, while fixing a few memory leaks, I was surprised at just how easy it is to unknowingly cause a serious memory leak by doing simple, mundane things in WPF. In this post, I will summarize the most common pitfalls to look out for.
Be careful when binding to a regular property
This is probably the easiest thing you can get wrong. Since most .NET properties are regular ones (not DependencyProperties), you’ll often find yourself binding to those. It is as easy as binding to a DependencyProperty and it works great. However, if the class that contains that property doesn’t implement the INotifyPropertyChanged interface, the binding may cause a memory leak, as described in this knowledge base article.
One way to fix it, as described in this blog post, is to make sure all your bindings to this object are defined with a BindingMode of OneTime. Alternatively, if possible, you can make your class implement INotifyPropertyChanged (even though you won’t necessarily be using it) , and add a comment that explains that you are adding it just to avoid this memory leak. That way, you can avoid having another programmer come along and add a new binding that re-introduces the leak.
Profiling tip: You can often identify this leak in your memory profiler by noting that the leaked object will be rooted by a static field of a class called ReflectTypeDescriptorProvider.
Don’t forget to call RemoveValueChanged after calling AddValueChanged
This is yet another “by design” catastrophe. If you want to know when a DependencyProperty changed and hook yourself up to DependencyPropertyDescriptor.AddValueChanged, you are essentially creating a static strong reference to your object.
By now you’re probably asking, “Well, why don’t you just make sure to call RemoveValueChanged when you’re done with it, you irresponsible, criminally negligent, leak-creating hack?”. “Ah!”, I would reply, “but when should you call RemoveValueChanged?” It’s likely that you’ve called AddValueChanged from within your WPF UIElement, but there is no truly reliable way (that I know of) to get informed when a UIElement is unloaded. This makes deterministically finding out the exact point in time in which you should clear your event handlers tricky.
WPF handles these sort of problems internally by a vast sprinkling of the Weak Event Design Pattern, and mostly leaves you to fend for yourself when it has caused you to bump against these “by design” memory leaks. How should you fight this evil? Well, my personal recommendation is to avoid using AddValueChanged entirely, and instead use thePropertyChangedNotifier class from Andrew Smith’s blog post.
You could also consider having your Static Code Analysis tools mark any usage of this method as an error, to avoid new programmers on your team re-introducing the same memory leak after you’ve fixed it.
Avoid binding to collections that are not ObservableCollection
I’m a bit sketchy on the details on this one. I haven’t yet been able to find the root cause of this issue, or find any corroborating blog post or MSDN articles, but still: in several instances, I’ve found memory leaks occurred when an ItemsControl was bound to an ICollection that isn’t an ObservableCollection, and changing it to an ObservableCollection solved the problem. If anyone knows more about this, please post a comment and share with the group.
That’s it for today. I wish you all a happy, leak-free day.