foreach 与 GC

自古以来,Unity 小伙伴就有使用for或者while循环而非foreach ,避免产生GC的概念。

原因

可以通过反编译dll查看IL代码,网上资料很多
例如 作为Unity3D的脚本而言,c#中for是否真的比foreach效率更高? - 王剑飞的回答 - 知乎
以及 Unity/C# 漫谈一:foreach与GC - 李路亚的文章 - 知乎

关于IEnumerable更详细的测试
关于foreach 的 GC测试

以下截取优质回答:

出现box是因为用了using语句,自己调用Dispose应该就没有这个问题了。Unity编译的代码会把值类型转换成接口类型,而接口类型属于引用类型,所以需要box到堆上才能callvirt。.NET编译的IL会使用constrained操作避免box,归根到底还是mono编译器不够优化的问题。具体可以看:OpCodes.Constrained Field (System.Reflection.Emit)

box valuetype:装箱,将值类型封装成valTypeToken指定的对象类型,流程是,弹出计算堆栈上的值类型参数,并使用新建立的一个引用类型对象进行并包装,将包装结果返回计算堆栈。本过程产生GC Alloc。

自己补充:
通过反编译代码,可以看到编译后的finally方法中对迭代器进行了装箱

现状

根据一些网友测试,unity 5.3.5.p8版本已经修复这个问题,
[网友测试](Unity 关于foreach产生GC的bug修复_好身亡的博客-CSDN博客
[官方论坛声明](C# Compiler - Upgraded C# Compiler on 5.3.5p8 - Unity Forum
自己还没做测试,如有错误,欢迎留言勘误!!

使用方法

当然实际开发假若还没有用到新版的mono compiler,建议使用如下方式:
List等结构使用 for 或者while 遍历,
Dictionary使用迭代器, 如下:

 var dic = new Dictionary();
 var enumerator = dic.GetEnumerator();
 while(enumertor.MoveNext())
 {
    // progress codes...
 }

注意事项

避免在update和协程循环体中使用 Linq

你可能感兴趣的:(foreach 与 GC)