As cutesy as it may be, I’m growing rather fond of my garbage collection count display. I’m especially fond of it because it helped me find garbage collections occuring in places I never expected them to happen. Such as my title screen for example:
Ack! Look at all those garbage cans, I mean recycling bins (reduce, reuse, recycle, folks!)
That’s a lot of garbage collections for a “static” title screen. Now, how to find out what’s causing all that garbage to be created… That’s where Microsoft’s CLRProfiler comes into play.
CLRProfiler is a great tool for profiling your XNA game’s memory usage. It can produce graphs and tables that tell you exactly when your game is allocating what classes. It’s also a bit rough around the edges and hard to use. Even installing it eschews the oh-so-common installer for a zip file (a rarity in Windows tools nowadays.)
So, once I get my hands on the tool, the first thing I have to do is get my game running with CLRProfiler. Pressing the Start Application button seems like a good place to start, but first I need to set my working directory or else my game won’t be able to find its data while it’s being run. To do that, I click on File->Set Parameters then set the working directory to the directory where my game’s executable lives.
Next, to make sure I get all the information I need, I enable both Allocations and Calls in the Profile section. With those settings done, I’m ready to hit the Start Application button and select my game’s executable for profiling.
Diagnosing the Problem
At this point, I let my game run to the title screen so I can gather data on memory applications. After a few seconds, I shut down my game and let CLRProfiler chew on the data and present it to me.
See that sawtooth pattern on the bottom timeline there? Those are garbage collections. Memory builds up until it hits a threshold then garbage collection kicks in and drops the total memory usage. After that memory begins to build up again until it hits the threshold and triggers another collection and so on. Now that I know how I’m allocating memory, it’s time to find out what I’m allocating. Box-selecting one of the sawtooths, I produce a report of what is in memory at that point.
The list on the right shows me all objects instantiated during the period I box-selected. Lots of System.Objects and lots of ActorStates. The ActorState structs are definitely being produced by my code and the System.Objects are probably being produced by the way I’m using .NET. Right-clicking on the list of allocated objects, I produce a graph of which function calls allocated which objects.
Aha, looks like ActorStates are being allocated when they are being compared. As for the System.Objects, it looks like my calls into the .NET’s Reflection code are responsible. Considering that RuntimePropertyInfo.SetValue() takes a System.Object as a parameter and my code is generally passing in value types, this looks like a textbook case of boxing.
Now, thanks to CLRProfiler, I know where my garbage collection problems are coming from. Next week, I’ll go into what I can do to fix them.