For a few days now I've been trying to track down the source of performance problems in my Windows Phone 7 game. It turns out the memory was increasing by an alarming rate when navigating around the different pages. Even just moving back and forth between the first page and a second page would cause it go over the magic 90 MB limit imposed by Microsoft certification.
I've heard some refer to this as a memory leak but I couldn't find too much information to help me. Something was blocking the garbage collector from disposing the old page when navigating back. On the advice from someone in the AppHub forums
, I added a disposer and put a break point in it to see if was ever getting called. I found one of the first things I needed to do was remove any event listeners that were running on a separate thread. The only one I had was added to a DispatchTimer that I was using for displaying memory usage at one second intervals. Easy enough and this won't be in the final build anyway.
The thing I had trouble finding was a call to performanceProgressBar.IsIndeterminate= true allowed the page to live when it should've been disposed. The performance progress bar is included in a separate toolkit available for download from MS
and is supposed to provide a smoothly animated WP7 style progress bar. The problem was that the page would get collected no problem if I clicked the hardware back button, but if I navigated back using the GoBack() method, the data would persist in memory! I don't know why this is because from what I understand, touching the back button just calls GoBack() anyway. I don't see why these two actions should give different results.
Eventually, I'd hit the 90 meg limit, performance would slow to crawl and finally the game would just exit. I assume this has something to do with it persisting in a separate thread, since this is how it achieves the smooth animation. So if you find yourself with this same problem, just remember to remove the progress bar from the UI child element list in your override of OnNavigatedFrom().
Fortunately, it appears that this is no longer a problem with the August update to the toolkit but until Mango is released it's still something you might need to handle. Additionally, I've found AdRotator
also blocks GC calls unless it's removed from the UI list as well. I suppose the best thing to do is put a dispose method in your page and check it often with a breakpoint to be sure it eventually gets destroyed. Or better yet, when running in debug mode, have it pop up a message box telling you it's disposed.
Anybody see any other GC blocking code out there?