lys*_*cid 20 .net c# clr foreach loops
我知道关于foreach循环如何在C#中工作的基础知识(foreach循环如何在C#中工作)
我想知道是否使用foreach分配可能导致垃圾收集的内存?(适用于所有内置的系统类型).
例如,在System.Collections.Generic.List<T>类上使用Reflector ,这里是GetEnumerator的实现:
public Enumerator<T> GetEnumerator()
{
return new Enumerator<T>((List<T>) this);
}
Run Code Online (Sandbox Code Playgroud)
在每次使用时,这将分配一个新的枚举器(和更多的垃圾).
所有类型都这样做吗?如果是这样,为什么?(不能重用一个枚举器吗?)
han*_*gar 51
Foreach可以导致分配,但至少在较新版本的.NET和Mono中,如果您正在处理具体System.Collections.Generic类型或数组,则不会.这些编译器的旧版本(例如Unity3D使用的Mono版本直到5.5)总是生成分配.
C#编译器使用duck类型来查找GetEnumerator()方法并在可能的情况下使用它.类型GetEnumerator()上的大多数方法System.Collection.Generic都有GetEnumerator()方法返回结构,并且数组是专门处理的.如果您的GetEnumerator()方法没有分配,通常可以避免分配.
但是,如果你正在处理的一个接口,你总是会得到分配IEnumerable,IEnumerable<T>,IList或IList<T>.即使您的实现类返回一个结构,该结构也将被装箱并转换为IEnumerator或IEnumerator<T>,这需要分配.
注意:由于Unity 5.5更新到C#6,我知道目前还没有第二次分配的编译器版本.
有一个第二个分配,要理解起来有点复杂.采取这个foreach循环:
List<int> valueList = new List<int>() { 1, 2 };
foreach (int value in valueList) {
// do something with value
}
Run Code Online (Sandbox Code Playgroud)
直到C#5.0,它扩展到这样的东西(有一些小的差异):
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();
}
Run Code Online (Sandbox Code Playgroud)
虽然List<int>.Enumerator是一个结构体,并且不需要在堆上分配,但是转换enumerator as System.IDisposable框是结构,这是一个分配.规范改变了C#5.0,禁止分配,但.NET 破坏了规范并更早地优化了分配.
这些分配非常小.请注意,分配与内存泄漏非常不同,并且通过垃圾回收,您通常不必担心它.但是,在某些情况下,您甚至不关心这些分配.我做Unity3D工作直到5.5,我们无法在每个游戏框架的操作中进行任何分配,因为当垃圾收集器运行时,你会得到明显的晃动.
请注意,数组上的foreach循环是专门处理的,不必调用Dispose.所以据我所知,foreach在循环数组时从未分配过.
不,枚举列表不会导致垃圾收集.
List<T>该类的枚举器不从堆中分配内存.它是一个结构,而不是一个类,所以构造函数不分配对象,它只返回一个值.该foreach代码将保持在栈上是价值,而不是在堆上.
其他集合的枚举器可能是类,它们会在堆上分配一个对象.您需要检查每个案例的枚举器类型是否确定.
| 归档时间: |
|
| 查看次数: |
12635 次 |
| 最近记录: |