Introduction:

  ※本文不是在描述旧版本Unity中mono编译器导致的foreach语句额外装箱错误

  博主是一名Unity 3D游戏开发者,游戏使用C#+lua开发,最近在优化C#代码时,发现了一处使用foreach不恰当的地方,其结果是造成了每帧近3k的GC Alloc,如此高频率的GC堆内存分配,会导致垃圾回收的调用更加频繁,从而影响游戏性能,而这只需要简单的修改即可避免;

  ※使用.Net 2.0的Unity版本,如果是较新的.Net 4.x版本,由于FCL实现修改,本文中48->56

  原始声明代码如下:

private readonly IDictionary<int, MyClass> mDic = new Dictionary<int, MyClass>();

  在每帧逻辑里面,会多次对其进行遍历,遍历代码如下:

foreach(var keyValuePair in mDic)
{
//do...
}

  通过Unity自带的Profiler分析,可以发现其导致的GC Alloc:

Body:

  通过上面的Profiler可以发现此时foreach语句实际上调用的是Dictionary定义中隐式实现的IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()方法,该方法的声明如下:

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
return new Enumerator(this, Enumerator.KeyValuePair);
}

  其中,Enumerator是在Dictionary类中定义的嵌套结构类型:

  结构类型隐式转换为接口类型时会发生装箱,对于该Enumerator类型,其装箱后大小为16(开销字节)+8(字段dictionary)+8(字段next+stamp)+16(字段current:8(int字节对齐)+8)=48字节,调用29次即产生48*29=1392字节的堆内存分配,这符合我们看到Profiler里面看到的GC Alloc;

  为了解决这个问题,只需要将变量声明时改为Dictionary即可,不使用接口类型的变量,即:

private readonly Dictionary<int, MyClass> mDic = new Dictionary<int, MyClass>();

  此时,在对mDic进行foreach循环时,就会调用Dictionary<TKey,TValue>.GetEnumerator()方法,该方法返回值类型即结构类型的Enumerator,避免了装箱操作:

One more thing:

  这里可能很多人有个误解,即foreach是只能对实现了IEnumerable或IEnumerable<T>的类型对象进行遍历,其实不然,foreach语句还可以对满足以下条件的任何类型的对象进行遍历:

  实现了可访问的GetEnumerator()方法,且该方法的返回值类型符合:包含可访问的Current属性和bool MoveNext()方法;

Conclusion:

  这样就知道了,.Net框架类库提供的泛型集合类型都实现了这样的方法,因此可以放心对泛型集合进行foreach遍历,而不产生堆内存的分配,也因此,我们在使用这些类型时,尽量避免直接对其接口类型的变量进行遍历;


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

作者:Minotauros
出处:https://www.cnblogs.com/minotauros/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

C#效率优化(3)-- 使用foreach时避免装箱的更多相关文章

  1. C#效率优化(1)-- 使用泛型时避免装箱

    本想接着上一篇详解泛型接着写一篇使用泛型时需要注意的一个性能问题,但是后来想着不如将之前的详解XX系列更正为现在的效率优化XX系列,记录在工作时遇到的一些性能优化的经验和技巧,如果有什么不足,还请大家 ...

  2. php程序效率优化的一些策略小结

    php程序效率优化的一些策略小结   1.在可以用file_get_contents替代file.fopen.feof.fgets等系列方法的情况下,尽量用 file_get_contents,因为他 ...

  3. php效率优化

    php效率优化 最近在公司一边自学一边写PHP程序,由于公司对程序的运行效率要求很高,而自己又是个新手,一开始就注意程序的效率很重要,这里就结合网上的一些资料,总结下php程序效率优化的一些策略:1. ...

  4. C#效率优化(4)-- 编译器对数组遍历的优化

    在平时开发过程中,数组是我们使用频率最高的类型之一,在使用定长列表时,数组可以说是最佳方案,这也是我们最熟悉的数据结构之一. 在C#中使用数组,可以获取在内存上连续的相同类型的一组变量,在连续访问时可 ...

  5. jquery选择器效率优化问题

    jquery选择器效率优化问题   jquery选择器固然强大,但是使用不当回导致效率问题: 1.要养成将jQuery对象缓存进变量的习惯 //不好的写法 $('#btn').bind("c ...

  6. php性能效率优化

    [size=5][color=Red]php性能效率优化[/color][/size] 最近在公司一边自学一边写PHP程序,由于公司对程序的运行效率要求很高,而自己又是个新手,一开始就注意程序的效率很 ...

  7. Jenkins Kubernetes Slave 调度效率优化小记

    Jenkins K8S Slave 调度效率优化 by yue994488@126.com 使用kubernetes为测试工具Gatling进行大规模压测,压测期间发现Jenkins调度压测实例较慢, ...

  8. 见招拆招-PostgreSQL中文全文索引效率优化

    * { color: #3e3e3e } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans ...

  9. Unity3d代码及效率优化总结

    1.PC平台的话保持场景中显示的顶点数少于200K~3M,移动设备的话少于10W,一切取决于你的目标GPU与CPU. 2.如果你用U3D自带的SHADER,在表现不差的情况下选择Mobile或Unli ...

随机推荐

  1. eclipse装了springboot插件后yml文件没有自动提示问题

    选择打开方式:spring yaml

  2. 探索未知种族之osg类生物---渲染遍历之Renderer简介

    我们继续renderingTraversals()的探究.我们接着上一节的”阻塞渲染线程”后就要遍历所有摄像机的渲染器(Renderer),执行 Renderer::cull 场景筛选的操作.我们在r ...

  3. redis使用规范文档 20170522版

    运维redis很久了,一直是口头给rd说各种要求,尝试把这些规范总结成文档 摘选一些可能比较通用的规则如下: 强制:所有的key设置过期时间(最长可设置过期时间10天,如有特殊要求,联系dba说明原因 ...

  4. NC 5导出Excel

    Excel导出功能 NC中功能事件代码: @Override protected void onBoRefresh() throws Exception { UIFileChooser fc = ne ...

  5. linux下面重启apche 与mysql服务

    1.service httpd restart 重启apache 2.service mysqld restart 重启mysql 开启与停止换成start与stop即可

  6. AJAX html 传输json字符串&&巧妙运用eval()来解析返回的JSON字符串

    1.AJAX html 传输json字符串: js方法如下: function saveRetYwlsh(){ var xmbh = document.getElementById("xmb ...

  7. Monotonic Array LT896

    An array is monotonic if it is either monotone increasing or monotone decreasing. An array A is mono ...

  8. java多线程系列11 juc包下的队列

    队列分为两类  阻塞队列 BlockingQueue提供如下两个支持阻塞的方法:   (1)put(E e): 尝试把e元素放如BlockingQueue中,如果该队列的元素已满,则阻塞该线程.   ...

  9. String 常用函数

    判断字符串是否包含指定字符str.contains("string"); 查找指定字符索引str.indexOf("s"'); 查找最后出现的字符索引str.i ...

  10. 学习:java集合

    java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE, JavaME, Jav ...