Using a memory profiling tool such as ANTS Memory Profiler from Red-Gate or MemProfiler from SciTech Software (I’m sure there others, but those were the only two I found that can profile a Silverlight Out-Of-Browser application) is a good idea. By using such a tool, developers can discover a myriad of memory leaks and fix them before releasing their code. These leaks usually stem from classes that attach event handlers to other classes. In fact, in my opinion, I’ve seen more memory leaks in Silverlight (and WPF) stemming from poor event handler management than anything else.
However, every once in a while, you’ll see something that appears to be unexplainable.
After profiling an application for a client, I discovered the usual gambit of event-handlers and strong-references between objects. In fact, an initial object retention graph (in this case, produced by the ANTS Memory Profiler) was almost indecipherable.
This is intentionally unreadable for two reasons: 1) to protect the innocent, and 2) because that graph is so big, there’s no way to actually show it in it’s entirety without massive scrolling (I could probably whip up a Deep Zoom for it, but that’s over kill for the purposes of this discussion).
The faint black box above the unreadable red “Start Here” box is the class I was researching, and the other boxes are classes in the hierarchy all the back to a GC root. So, you can see that there were a lot. After days of tracking down each strong reference and removing them, I ended up with a single chain.
This picture showed a ListBoxAutomationPeer as the last entity before being stuffed into the ManagedPeerTable.
My original object (the dark gray box) was never released and since this was one child view inside a parent container, multiple copies stayed in memory never to be garbage collected.
As far as memory consumption goes, it wasn’t too bad. And since all the event handlers were removed, and all messages unsubscribed to, the object just floated in the ether being unobtrusive. But, after spending days trying to clean up memory leaks, this was still unacceptable, especially since there were literally hundreds of these objects floating around.
The Automation framework was created as a method for adding accessibility or automated testing to your applications. The AutomationPeers are the way your application can communicate with Automation clients, or the way the Automation clients can communicate with your application.
If an Automation Client is running, it can and will ask your application if it supports automation. For both Silverlight and WPF this happens automatically (no pun intended). Sometimes the client is nice about it and requires that you attach it to your application (like most automated testing frameworks).
In my case, I wasn’t running an automated testing framework. I wasn’t creating an Automation Client at all and attaching it to my application. But AutomationPeers were being created, nonetheless.
So, I tested this application on a co-workers machine to see if there was something environmental causing the problem. As fate would have it, there was. His computer was not showing this memory leak.
After a day or two of digging around I realized that my computer was running Tablet PC Input Services (I have a Wacom tablet and the Tablet PC Input Services was installed when Windows figured out I had pen-enabled computer).
Turning off the Tablet PC Input Services removed the AutomationPeers from the object retention graph and the memory leak was plugged.
Unfortunately, nothing in the ANTS Memory Profiler or MemProfiler indicated that Tablet PC Input Services was the culprit causing the AutomationPeers to be created. Additionally, while it seems like I’m pointing a finger at TIPS, any AutomationClient would probably cause the same issues within the application.
In conclusion, when looking for memory leaks, be aware that the automation API can keep your objects alive for longer than you expect. You can mitigate bugs this may cause by properly detaching objects from external events and removing strong references to existing objects when you dispose or unload them. Finally, profile your application frequently as lots of things can show up that may help you fix issues before they escalate into week-long bug hunts.