优化-CPU

2018-06-15  本文已影响0人  叫我颜先生

原文地址:https://blog.uwa4d.com/archives/optimzation_cpu.html
http://www.cnblogs.com/chwen/p/4396515.html

CPU方面的性能开销主要两大类:引擎模块和自身代码。其中,引擎模块中又可细致划分为渲染模块、动画模块、物理模块、UI模块、粒子系统、加载模块和GC调用等等。
主要就是drawcall、物理组件、GC(垃圾回收)、脚本等几个方面开展

渲染模块

1.DrawCall

Drawcall是CPU向GPU发送绘制命令的接口调用。理论上每一个不同材质的物件需要渲染在屏幕上时,CPU都会调用图形API ( openGL or Diract3D ) 的Draw接口触发显卡进行绘制。
如果每次drawcall只提交少量的数据将导致CPU瓶颈,CPU无法将GPU填满。Drawcall对GPU的耗费在于硬件一直等待CPU提交数据,而无法得到有效利用。GPU大量的时间耗费在不断切换状态和正确性检测上。 实际上unity官方指出,Drawcall数量的降低并非重点,重点是减少批次的数量,Drawcall优化实际上是对批次数量的优化

优化方案:Drawcall batching,合并打包图集,减少光照和阴影等

2.LOD(https://blog.csdn.net/u014306293/article/details/72522834)

LOD技术指根据物体模型的节点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算,就是根据与摄像机的距离来选择不同精密物体渲染

3.Occlusion Culling(https://blog.csdn.net/qq_33747722/article/details/70549006)

遮挡剔除、视锥剔除,这两个Unity提供的剔除方案,出视野之后应剔除对象渲染。

加载模块

仅次于渲染的第二大模块,主要包括资源加载,卸载,实例化,代码序列化
cpu开销在引擎中主要体现在Loading.UpdatePreloading和Loading.ReadObject两项中(Profiler)

1.纹理加载

纹理资源是项目加载过程中开销占用最大的资源之一,其加载效率由其自身大小决定。目前,决定纹理资源大小的因素主要有三种:分辨率、格式和Mipmap是否开启

2.网格加载

加载效率由自身大小决定

3.Shader加载

一个Shader资源的物理Size仅几KB,在内存中也不过几十KB。所以,Shader资源的效率加载瓶颈并不在其自身大小的加载上,而是在Shader内容的解析上。几个小小的Shader,其加载耗时居然要高于几张Atlas纹理或者拥有上万片面的Mesh网格。

4.场景加载
  1. 场景加载

    • 资源加载:资源加载几乎占据了整个加载过程的90%时间以上,其加载效率主要取决于资源的加载方式(Resource.Load或AssetBundle加载)、加载量(纹理、网格、材质等资源数据的大小)和资源格式(纹理格式、音频格式等)等等。不同的加载方式、不同的资源格式,其加载效率可谓千差万别
    • Instantiate实例化:在场景加载过程中,往往伴随着大量的Instantiate实例化操作,比如UI界面实例化、角色/怪物实例化、场景建筑实例化等等。在Instantiate实例化时,引擎底层会查看其相关的资源是否已经被加载,如果没有,则会先加载其相关资源,再进行实例化,这其实是大家遇到的大多数“Instantiate耗时问题”的根本原因,这也是为什么我们在之前的AssetBundle文章中所提倡的资源依赖关系打包并进行预加载,从而来缓解Instantiate实例化时的压力
  2. 场景卸载
    对于Unity引擎而言,场景卸载一般是由引擎自动完成的,即当我们调用类似Application.LoadLevel的API时,引擎即会开始对上一场景进行处理

    • Destory:引擎在切换场景时会收集未标识成“DontDestoryOnLoad”的GameObject及其Component,然后进行Destroy.同时,代码中的OnDestory被触发执行,这里的性能开销主要取决于OnDestroy回调函数中的代码逻辑
    • Resources.UnloadUnusedAssets:一般情况下,场景切换过程中,该API会被调用两次,一次为引擎在切换场景时自动调用,另一次则为用户手动调用(在场景加载后,用户调用它来确保上一场景的资源被卸载干净).该API的CPU开销主要集中在500ms~3000ms之间.其耗时开销主要取决于场景中Asset和Object的数量,数量越多,则耗时越慢

UI模块

物理模块

GC调用

GC是unity自动回收内存垃圾的回收器,这虽没有内存泄漏的风险,但是过多的垃圾回收会让CPU高负荷。这里就要避免不必要的内存申请和释放。可以在某个脚本定时清理垃圾,如void update(){if(Time.framecount %5 ==0)System.GC.collect();}
有以下几点需要注意:

  1. 字符串的拼接会产生临时字符串内存,移除代码中的字符串拼接,改用string.format,或stringbuilder,这没测。
  2. 用for代替foreach,foreach每次迭代产生24字节垃圾内存。100次循环就是2.4kB.
  3. 对象标签tag比较采用comparetag,不要用tag=="mytag"这样。
  4. 使用对象池。对象克隆也是调用new,因此对于可以循环利用的对象要采用对象池,比如子弹、特效、宝石等等。
  5. 尽量使用struct而非class,因为struct是栈区,class是堆区。

Unity官方给出的一些优化建议:

  1. PC平台的话保持场景中显示的顶点数少于200K~3M,移动设备的话少于10W,一切取决于你的目标GPU与CPU。
  2. 如果你用U3D自带的SHADER,在表现不差的情况下选择Mobile或Unlit目录下的。它们更高效。
  3. 尽可能共用材质。
  4. 将不需要移动的物体设为Static,让引擎可以进行其批处理。
  5. 尽可能不用灯光。
  6. 动态灯光更加不要了。
  7. 尝试用压缩贴图格式,或用16位代替32位。
  8. 如果不需要别用雾效(fog)
  9. 尝试用OcclusionCulling,在房间过道多遮挡物体多的场景非常有用。若不当反而会增加负担。
  10. 用天空盒去“褪去”远处的物体。
  11. shader中用贴图混合的方式去代替多重通道计算。
  12. shader中注意float/half/fixed的使用。
  13. shader中不要用复杂的计算pow,sin,cos,tan,log等。
  14. shader中越少Fragment越好。
  15. 注意是否有多余的动画脚本,模型自动导入到U3D会有动画脚本,大量的话会严重影响消耗CPU计算。
  16. 注意碰撞体的碰撞层,不必要的碰撞检测请舍去。
上一篇 下一篇

猜你喜欢

热点阅读