C#效率优化(3)-- 使用foreach时避免装箱
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时避免装箱的更多相关文章
- C#效率优化(1)-- 使用泛型时避免装箱
本想接着上一篇详解泛型接着写一篇使用泛型时需要注意的一个性能问题,但是后来想着不如将之前的详解XX系列更正为现在的效率优化XX系列,记录在工作时遇到的一些性能优化的经验和技巧,如果有什么不足,还请大家 ...
- php程序效率优化的一些策略小结
php程序效率优化的一些策略小结 1.在可以用file_get_contents替代file.fopen.feof.fgets等系列方法的情况下,尽量用 file_get_contents,因为他 ...
- php效率优化
php效率优化 最近在公司一边自学一边写PHP程序,由于公司对程序的运行效率要求很高,而自己又是个新手,一开始就注意程序的效率很重要,这里就结合网上的一些资料,总结下php程序效率优化的一些策略:1. ...
- C#效率优化(4)-- 编译器对数组遍历的优化
在平时开发过程中,数组是我们使用频率最高的类型之一,在使用定长列表时,数组可以说是最佳方案,这也是我们最熟悉的数据结构之一. 在C#中使用数组,可以获取在内存上连续的相同类型的一组变量,在连续访问时可 ...
- jquery选择器效率优化问题
jquery选择器效率优化问题 jquery选择器固然强大,但是使用不当回导致效率问题: 1.要养成将jQuery对象缓存进变量的习惯 //不好的写法 $('#btn').bind("c ...
- php性能效率优化
[size=5][color=Red]php性能效率优化[/color][/size] 最近在公司一边自学一边写PHP程序,由于公司对程序的运行效率要求很高,而自己又是个新手,一开始就注意程序的效率很 ...
- Jenkins Kubernetes Slave 调度效率优化小记
Jenkins K8S Slave 调度效率优化 by yue994488@126.com 使用kubernetes为测试工具Gatling进行大规模压测,压测期间发现Jenkins调度压测实例较慢, ...
- 见招拆招-PostgreSQL中文全文索引效率优化
* { color: #3e3e3e } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans ...
- Unity3d代码及效率优化总结
1.PC平台的话保持场景中显示的顶点数少于200K~3M,移动设备的话少于10W,一切取决于你的目标GPU与CPU. 2.如果你用U3D自带的SHADER,在表现不差的情况下选择Mobile或Unli ...
随机推荐
- javaweb开发3.基于Servlet+JSP+JavaBean开发模式的用户登录注册
转载孤傲苍狼博客http://www.cnblogs.com/xdp-gacl/p/3902537.html 1.层次比较分明的项目结构图
- 在桌面创建robotframework Ride的快捷方式启动RIDE
安装后robotframework-ride 后,每次启动时都要在Dos命令下启动 ,下面是创建快捷方式启动操作如下: 1.进入到python的安装目录的/Scripts目录下,找到ride.py文件 ...
- Python 多个分隔符 读取逗号和空格分开的数据
str.split() 清除默认 空格和tab 对空格数量不敏感 str.split(' ') 只清除一个空格 对空格数量敏感 l = re.split('[^0-9.]+',s.stri ...
- Fefora 14 源
默认的源不能用,需要用下边的源路径. [fedora] name=Fedora $releasever - $basearch failovermethod=priority #baseurl=htt ...
- [SoapUI] 如何同时调用Global Script Library(放在SoapUI安装目录)和项目特有的Script Libary(放在项目代码下)
SoapUI 支持引入多个package: Global Script library : 在SoapUI工具File->Preference中设置Project Script Library: ...
- 设计模式之桥接模式 c++11
参考http://blog.csdn.net/calmreason/article/details/50909321 桥接模式 实现与抽象之间由指针关联 调用sample类 实际是调用sample类保 ...
- java多线程系列12 ConcurrentHashMap CopyOnWriteArrayList 简介
我们知道 ,hashmap 和 arraylist 是线程不安全的 在多线程环境下有数据安全问题, 当然 我们可以通过Collections的一些方法把他们变成线程安全的, Collections.s ...
- Python数字与字符之间的转换
Python数字与字符之间的转换 命令 意义 int(x [,base ]) 将x转换为一个整数 long(x [,base ]) 将x转换为一个长整数 float(x ) 将x转换到一个浮点数 co ...
- C程序编程规范一
和身边一些学弟们接触发现他们的编程习惯不是太好,对一些基本的规范不重视,今天有时间写一些基本的规范给一些刚入门的新手们,高手可忽略. 首先做项目来说需要建立工程,一般需要几个到几百个上上千个C文件,这 ...
- 【pycharm 警告】unittest RuntimeWarning: Parent module ” not found while handling absolute import
Pycharm 2016.2执行单元测试遇到如下问题: RuntimeWarning: Parent module ‘YOUR_MODULE_HERE’ not found while handlin ...