Memory Issues? Not to worry.
In QuickUnit we develop a Visual Studio addin which allows developers to easily create quality unit tests. It’s a rather complicated, highly extensible, code-analysis and code-generation, .net application, with a rather complex UI layer (but with a simple UX). We use WPF (on MVVM) for the UI infrastructure, and make very heavy use of viewmodel objects, data bound to data templates.
We’ve encountered a scenario where our memory consumption started growing, after every action which basically only re-rendered the UI. ProcessExplorer was kind enough to show us that the gen2 heap was growing steadily, and GC collections had no effect. Basically, the classic telltale signs of a managed memory leak.
Our first mistake was to try to find the leak manually, by code reviews. We’re a strong, two-man team, and we know the code pretty darn well, so we figured this was only a matter of catching the ill-written line or two. The second mistake was finding an ill-written line or two which made us feel good about solving the problem. J
After realizing that our solution did not help one bit – we told ourselves to get serious about it, and start profiling. Oh, the Ants Memory profiler kicks so much ass... After adding a “GC Collect” button to our application (a great feature to have in any memory profiler, btw) we were good to go.
We’ve distilled the least amount of work required to recreate the leak, took a memory snapshot for the “before”, performed that action 5 times, and then took another snapshot (actually, add “frantically pressing the GC Collect button” before any snapshot). The reason to do the action 5 times was to easily identify which objects count grew by a multiply of 5, since some objects are added for valid reasons, and do get cleaned between actions. I don’t know if it’s a best practice, but it works).
After finding such type (which has a multiple of 5 new instances) – reviewing the reference graph for one such instance is dead simple. I am, however, dead stupid, so I offset it a bit: they put a large red box at the bottom of the screen, next to the relevant instance, with a big red arrow stating “START HERE”, but I keep ignoring it, and go straight to the GC roots. Something inside me keeps telling me that it’s more important. I can’t fight it. Only after I’m persuaded to start following the graph from the right place – I can start seeing the problems.
The problem was, btw, the old familiar case of databinding to a non-INotifyPropertyChanged object, which, well… leaks. We just missed that databinding in our code review.
Other good memory leaks:
http://blogs.msdn.com/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx