I know the basics on how foreach loops work in C# (How do foreach loops work in C#)
I am wondering whether using foreach allocates memory that may cause garbage collections? (for all built in System types).
For example, using Reflector on the System.Collections.Generic.List<T>
class, here's the implementation of GetEnumerator:
public Enumerator<T> GetEnumerator() { return new Enumerator<T>((List<T>) this); }
On every usage this allocates a new Enumerator (and more garbage).
Do all types do this? If so, why? (can't a single Enumerator be reused?)
Foreach can cause allocations, but at least in newer versions . NET and Mono, it doesn't if you're dealing with the concrete System. Collections. Generic types or arrays.
Every iteration of every “foreach” loop generated 24 Bytes of garbage memory.
How Does It Work? The foreach loop in C# uses the 'in' keyword to iterate over the iterable item. The in keyword selects an item from the collection for the iteration and stores it in a variable called the loop variable, and the value of the loop variable changes in every iteration.
The foreach loop is mainly used for looping through the values of an array. It loops over the array, and each value for the current array element is assigned to $value, and the array pointer is advanced by one to go the next element in the array. Syntax: <?
Foreach can cause allocations, but at least in newer versions .NET and Mono, it doesn't if you're dealing with the concrete System.Collections.Generic
types or arrays. Older versions of these compilers (such as the version of Mono used by Unity3D until 5.5) always generate allocations.
The C# compiler uses duck typing to look for a GetEnumerator()
method and uses that if possible. Most GetEnumerator()
methods on System.Collection.Generic
types have GetEnumerator() methods that return structs, and arrays are handled specially. If your GetEnumerator()
method doesn't allocate, you can usually avoid allocations.
However, you will always get an allocation if you are dealing with one of the interfaces IEnumerable
, IEnumerable<T>
, IList
or IList<T>
. Even if your implementing class returns a struct, the struct will be boxed and cast to IEnumerator
or IEnumerator<T>
, which requires an allocation.
NOTE: Since Unity 5.5 updated to C# 6, I know of no current compiler release that still has this second allocation.
There's a second allocation that is a little more complicated to understand. Take this foreach loop:
List<int> valueList = new List<int>() { 1, 2 }; foreach (int value in valueList) { // do something with value }
Up until C# 5.0, it expands to something like this (with certain small differences):
List<int>.Enumerator enumerator = valueList.GetEnumerator(); try { while (enumerator.MoveNext()) { int value = enumerator.Current; // do something with value } } finally { IDisposable disposable = enumerator as System.IDisposable; if (disposable != null) disposable.Dispose(); }
While List<int>.Enumerator
is a struct, and doesn't need to be allocated on the heap, the cast enumerator as System.IDisposable
boxes the struct, which is an allocation. The spec changed with C# 5.0, forbidding the allocation, but .NET broke the spec and optimized the allocation away earlier.
These allocations are extremely minor. Note that an allocation is very different from a memory leak, and with the garbage collection, you generally don't have to worry about it. However, there are some scenarios when you do care about even these allocations. I do Unity3D work and until 5.5, we couldn't have any allocations in operations that happen every game frame because when the garbage collector runs, you get a noticeable lurch.
Note that foreach loops on arrays are handled specially and don't have to call Dispose. So as far as I can tell, foreach has never allocated when looping over arrays.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With