- 1、本文档共9页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 5、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 6、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 7、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 8、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
IUnityC内存和性能优化技巧
Unity C#内存和性能优化技巧
游戏开发要学习的第一件事就是不分配不必要的内存。这样做有很充分的理由。第一,内存是一种有限资源,尤其是在移动设备上。第二,分配内存需要消耗CPU周期(在堆上分配和回收都消耗CPU周期)。第三,在C或C++中手动管理内存,每次分配内存都是引入Bug的契机,Bug会引起严重问题,任何地方的内存泄露都会引起崩溃。
Unity使用.Net或者可以说是一个开源替代品Mono。它的自动内存管理解决了大量安全问题,例如,不能在内存被释放后再使用(忽略了不安全代码)。但是,分配和释放内存变得更加难以预测。
假设你已经很了解栈分配和堆分配的区别。简而言之,堆栈数据生存周期比较短,分配/释放几乎不会消耗CPU。堆数据生命周期比较长,分配/释放消耗多些,因为,内存管理器需要跟踪内存分配。在.Net和Mono种,堆内存通过垃圾回收器自动获取。实际上,可以说是个黑盒,用户无法对其进行很多控制。
.Net的两种数据类型分配方式不同。实例的引用类型总是在堆上分配,然后被GC回收,例如,类、数组(如int[])。数据的值类型在堆栈分配,除非他们的容器已经在堆上(如数组结构),例如基本类型(int,char等)或者结构体实例。最后,值类型可以通过传递引用而从堆栈数据变成堆数据。
好了,开场结束。让我们谈谈垃圾回收和Mono。
罪过
找到并回收堆上数据是GC的工作,不同的回收器在性能上差异很大。
旧的垃圾回收器因为会产生帧率问题而臭名昭著。例如,一个简单的标记-清除回收器(阻塞回收器),会暂停整个程序,以便一次处理整个堆。暂停时间取决于程序分配的数据数量,如果暂停时间很长,会产生长时间无响应。
新的垃圾回收器在减少回收暂停方面有不同的方法,例如,现代GC通过在同一位置对所有最近分配进行分组,这样就可以扫描并快速收集被拆分的小块。因为,很多程序喜欢分配可以快速使用和丢弃的临时对象,将它们放在一起管理,有助于GC更快的响应。
不幸的是,Unity并不支持这些功能。Unity使用的是Mono 2.6.5版本,其GC是旧版的Boehm GC,不属于现代GC。我相信,也不支持多线程。最新版本的Mono已经有了更好的垃圾回收器,然而,Unity并没有升级。反之,他们正在计划使用其它方法来替代。
虽然这听起来像是一个令人兴奋的改进,但现在我们不得不忍受Mono 2.x 和旧的GC一段时间。
换句话说,我们需要最小化内存分配。
机会
每个人的首要建议都是使用单元数组时用for循环取代foreach循环。这很令人惊讶,foreach循环是代码更加可读,为什么我们要摆脱foreach呢?
原因是foreach循环在内部创建了一个新的枚举实例,foreach循环用伪代码表示如下:
foreach (var element in collection) { … }
编译之后如下:
var enumerator = collection.GetEnumerator();
while (enumerator.MoveNext()) {
var element = enumerator.Current;
// the body of the foreach loop
}
这有下面几个后果:
1. 使用枚举意味着需要额外的函数调用来遍历集合
2. 另外:Unity附带的Mono C#编译器有个Bug,foreach循环在堆上抛出一个对象,以至于GC在之后才会清理 (更多细节见this discussion thread)。
3. 编译器不会尝试把foreach循环优化成for循环,即使是简单的List集合(除了一个特殊优化,就是Mono把通过数组使用的foreach转化为for循环)。
让我们比较一下拥有16M元素的List和int[]的for、foreach循环。每种里面都使用一个Linq扩展。
// const SIZE = 16 * 1024 * 1024;
// array is an int[] // list is a List
1a. for (int i = 0; i SIZE; i++) { x += array; }
1b. for (int i = 0; i SIZE; i++) { x += list; }
2a. foreach (int val in array) { x += val; }
2b. foreach (int val in list) { x += val; }
5. x = list.Sum(); // linq extension
time memory
1a.
文档评论(0)