Foreach and Garbage, Part 2
As promised, here's a bit more about foreach and garbage. Last time I wrote about the Windows Desktop CLR. This time I want to find out if my results hold true on the Xbox 360 as well.
What did I find out last time?
"When doing a foreach over a Collection<T> an enumerator WILL be allocated.
When doing a foreach over most other collections, including as arrays, lists, queues, linked lists, and others:
if the collections are used explicitly, an enumerator will NOT be allocated.
if they are cast to interfaces, an enumerator WILL be allocated."
For you impatient readers, here's my results: As I just found out, this holds true on the Xbox360 as well. Read on to find out how I came to this conclusion, and maybe learn something about (deep breath) The XNA Framework Remote Performance Monitor for Xbox 360.
Although the Remote Performance Monitor (RPM) is extremely useful, it gives you less data than the Desktop CLR profiler that I used last time. I'm not an expert on how to use the tool, but I couldn't figure out how to figure out what types of objects were allocated. So, how can I figure out if an enumerator is being allocated or not?
Luckily, the RPM is more realtime than the desktop CLR profiler: it'll give you information on allocations as they happen. So, hopefully I can make a game that makes no allocations per frame, and verify that in the RPM. After the game finishes initializing, the RPM should report that no new objects were allocated. To test whether or not different foreach loops create garbage, I can change my game's Update to do a foreach. If the RPM reports that objects are now being allocated, I can assume that an enumerator was allocated.
So, to start, I'm creating a new Xbox360 game using the default template. I called my game ForeachXbox. I didn't change anything, just F5 to build and deploy it. Now I'm ready to use the RPM to verify that this game causes no per-frame allocations.
I followed this document for instructions on how to set up the Remote Performance Monitor, entering ForeachXbox as the name of my game. (You can ignore the instructions on how to use PerfMon.exe, we won't be using that.) I hit launch, scroll down to the GC section, and after a few seconds, the Remote Performance Monitor should show something like this:
The bit that we're interested in is Managed Objects Allocated. Notice how that's 0? This is a Good Thing.
So now lets start testing the rules that we came up with for the Desktop CLR. Switch back to Visual Studio, and we'll change the Game code a bit. We'll create the same GameEntity class as last time:
class GameEntity
{
public void Update()
{
}
}
and add a Collection of those to our game.
Collection<GameEntity> entityCollection = new Collection<GameEntity>();
I'll add ten game entities to this collection in the game's constructor. Then in the game's update, I'll just foreach over the collection:
foreach (GameEntity entity in entityCollection)
{
entity.Update();
}
Then hit F5 to build and deploy the game. Quit the game, and then launch it again using RPM. After the game finishes initializing, you should see something like this:
As expected, there's those allocations. And from the looks of it, it seems like RPM collects data about once a second.
Now that I know this, if I want to check to see if different foreach loops allocate or not, all I have to do is just change my code to use that foreach then run it using the RPM. If it allocates, it'll show up in that lovely little Delta column. This is how I verified that the Xbox 360 foreach behaves the same as foreach on the desktop CLR.
Hope this helps. I didn't dive too much into how to use the Remote Performance Monitor, I know. I haven't used it much, but it seems like a very useful tool. If I find myself doing something really neat with it in the future, I'll be sure to write about it.
Comments
- Anonymous
April 19, 2007
Everyone is writing about how to use profiling tools today. Must be something in the water... SwampThingTom