首先总结一下结论:在Unity5.2.3及以前,使用Foreach遍历List集合每次会产生40B的垃圾,会引起GC.在此版本之后Unity修复了该bug,使用Foreach的速度会更快.
1.mono在.net 3.5运行环境下,有bug会导致foreach效率比for慢。
2.mono在.net 4.0运行环境下,该bug修复,以下测试结果表明foreach比for快。
3.对于数组,在外部定义一个length循环比直接使用array.length的效率更低,是负优化。
foreach与for的区别:
foreach遍历数组无法改变数组的内容;
for可以,如果只是遍历则尽量用foreach.这样效率会更高.
C#的 foreach 语句是从 do,while,或者 for 循环语句变化而来的,它相对要好一些,它可以为你的任何集 合产生最好的迭代代码。它的定义依懒于.Net 框架里的集合接口,并且编译器会为实际的集合生成最好的代码。当 你在集合上做迭代时,可用使用 foreach 来取代其它的循环结构。
检查下面的三个循环:
<strong>int [] foo = new int[100];
// Loop 1:
foreach (int i in foo)
Console.WriteLine(i.ToString());
// Loop 2:
for (int index = 0; index < foo.Length; index++)
Console.WriteLine(foo[index].ToString());
// Loop 3:
int len = foo.Length;
for (int index = 0; index < len; index++)
Console.WriteLine(foo[index].ToString());</strong>
对于当前的 C#编译器(版本 1.1 或者更高)而言,循环 1 是最好的。
起码它的输入要少些,这会使你的个人开 发效率提提升。(1.0 的 C#编译器对循环 1 而言要慢很多,所以对于那个版本循环 2 是最好的。)
循环 3,大多数 C 或者 C++程序员会认为它是最有效的,但它是最糟糕的。因为在循环外部取出了变量 Length 的值,从而阻碍了 JIT 编译器将边界检测从循环中移出。
C#代码是安全的托管代码里运行的。环境里的每一块内存,包括数据的索引,都是被监视的。稍微展开一下,
循环 3 的代码实际很像这样的:
// Loop 3, as generated by compiler: int len = foo.Length;
for (int index = 0; index < len; index++)
{
if (index < foo.Length)
Console.WriteLine(foo[index].ToString());
else
throw new IndexOutOfRangeException();
}
C#的 JIT 编译器跟你不一样,它试图帮你这样做了。你本想把 Length 属性提出到循环外面,却使得编译做了 更多的事情,从而也降低了速度。CLR 要保证的内容之一就是:你不能写出让变量访问不属于它自己内存的代码.在访问每一个实际的集合时,运行时确保对每个集合的边界(不是 len 变量)做了检测。你把一个边界检测分成了两个。