Here's another post by someone who has learned everything through mistakes, not learning it right in the first place . :)
I've been working on some nasty GC issues on Xbox360 for some time now, and through RPM and CLR Profiler I've started to make some sense of things, so I thought I'd let everyone in on my experience so that the next guy (or gal) with these issues can have some info. So here's the story: Remote Performance Monitor showed 240 boxed value types per delta. Having no idea how I was creating boxed objects (or what they are), I ran the CLR profiler--as it would happen, I had 4 foreach calls per frame--for a postprocessing effect. According to CLR Profiler, the foreach calls were creating System.Collections.Generic.List<T>s. I switched
foreach (EffectPass pass in hazeEffect.CurrentTechnique.Passes)
to
EffectPass pass = hazeEffect.CurrentTechnique.Passes[0];
as there was only 1 pass in the effect anyway, and now I get 0 boxed objects per frame!
I guess the bottom line is that I never really used foreach calls, don't trust them, and now I've got better reason to! The part that was the culprit was a snippet I took from a tutorial.
The other GC issue I had was with tons of string.ToLower() calls. My character definition class gives animations string names, and each animation frame has a script; anyway, there were .toLower()s everywhere; I moved them all to load time and that's improved GC performance by about 3000ms per collection.
I guess the moral is avoid foreach and string.ToLower(), unless you know what you're doing, which I do not. Can anyone concur/provide the correct explanation

The woes of boxed objects (and foreach)
Alexandre Martins
Any type that implements the IEnumerable interface, which is all of the collection classes.
Basically, using foreach on an array is a special case since that's a built-in type. In all other cases, the only way foreach can know how to iterate through the elements is by using the IEnumerable interface.
Edit: fixed interface name... whoops.
Al42
edsela
Peter McEvoy
The foreach statement will create garbage because it needs to allocate an enumerator instance. If you use a disassembler to look at the code created when you do a foreach, a statement like:
foreach (MyType t in myCollection)
...
basically translates into:
IEnumerator<MyType> enumerator = myCollection.GetEnumerator();
while (enumerator.MoveNext())
{
MyType t = enumerator.Current;
...
}
For most collection types, the GetEnumerator method will have to allocate a new enumerator object, so this creates one piece of garbage per enumeration. Not a problem for things you only do a few times a frame (and I'm a big fan of foreach for the extra readability it can give) but this can be bad if you're doing it many times a frame.
If you think about it, the ToLower method is always going to create garbage, because it returns a modified version of the string, so it has to allocate new memory to hold this new version.
RaphaelGray
when I compile not on the compact framework, a foreach loop through a List<ValueType> is optimized to be only local variables (stack alloc not gc):
// types enumerator as a ValueType instead of interface to prevent boxing List<ValueType>.Enumerator enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) { ValueType t = enumerator.Current; ... }You could also just use a for(;;). I don't think replacing the foreach with either of these is less readable and I personally don't think it is premature optimization. Though I do agree you should minimize upfront optimization, when you have domain knowledge of a problem I think a little upfront optimization is ok.
beto81
R.Tutus
I'm a big fan of
for(int i = 0; i < array.length; i++)
having grown up on the VB
for i = 0 to UBound(array)
slyi
gafferuk