Unity学习-优化_卡顿缘由定位以及优化方案

除了Unity的一些组件优化技巧以外,更多的细节处于代码层面上算法

最近学习优化,看到一篇文章,写的很详细,从底层原理到咱们windows

的实际处理,都有一些很是好的建议,能够推荐给小伙伴们看看缓存

https://www.jianshu.com/p/289de89a6609性能优化

===========如何定位程序的哪个环节产生了过大的开销============ide

使用Uinty的Profiler工具,能够比较精准快速的定位程序的哪个位置产生了大开销工具

首先在build setting里面勾选Autoconnect Profiler性能

而后在windows栏选择proflier便可学习

 

打开以后便可监控游戏每一帧的运行状态了,能够根据FPS和每一帧运行的时间判断游戏的卡顿程度优化

肯定某一帧的占用率太高以后ui

 

点击波状图,就会暂停游戏

下方就会列出当前游戏运行的消耗详细信息了

跟进total栏的百分比,便可定位是哪一个位置产生了最大的消耗,从而进行相应优化了

这个工具是用来定位优化点的,具体的优化方案能够参考下面的优化方式

因为篇幅有限,并且这个工具应该大部分人都知道并且会用,就不过多赘述了。

不明白的能够参阅这篇做者的 https://www.jianshu.com/p/a7cee5e548cf 

写的很是详细

==================代码层优化====================

1、内存管理

  1:GC原理

      C#的垃圾回收是自动托管的,垃圾回收系统也有一套生命周期和统计流程,下面就是关于GC的总体流程:

    1)一次GC的过程分为2个阶段:

                标记清除阶段,GC会假设堆中全部对象均可以被回收,而后找出不能回收的对象,打上清除标记,剩下的就是要被回收的了。找的过程就是检查对象  有没有被其余的对象引用的过程,若是这个对象在程序中没有被引用到,那么就会被打上清除的标记。

               从新地址排列阶段,标记清除的对象被清除以后,堆里面的空间就会变成不是连续的了,GC的第二部就会开始从新排列还存在的对象,使堆中的地址  分配变成连续的。

    2)整个.net的GC流程:  

                在进行.Net的GC阶段,是不止一次GC操做的,C#采用了分代算法,先对程序里面的内存进行分代管理,再根据不一样的代,进行不一样力度的清理。

这里面的生命周期为3代, 第0代是新建立的代码,在达到了0代集合的阈值以后,触发0代的GC,幸存的对象会进入1代集合, 同理,在1代集合达到了阈值    的时候,也会进行GC,可是此次GC是 0代和1代一块儿执行,以此类推,2代集合GC的时候也会进行1代 2代的CG操做。按消耗量的比例应该是 1:10:100

这种分代算法是基于 老的对象生命周期通常都比新的对象生命周期长,就像公司的员工同样,时间较长的员工公司看来通常都比新进来的员工稳定性要大。

      2:优化策略

    明白了大体GC的流程以后会发现,GC会消耗大量的CPU性能,由于这里面会经历不少次的运算以及遍历等

    接下来是弄清楚GC何时被触发,以及如何规避影响用户体验的GC操做

    什么时候会触发GC?
    三种状况下会触发GC:

    1:跟进分代算法,在容量达到阈值的时候会发生,

    2:GC会不时的自动运行(频率因平台而异)。

    3:手动强制调用GC

        大体的优化思路就是 下降每一次GC的运行时间(减小垃圾对象,使GC的过程当中尽可能少的遍历),下降GC的频率(下降触发GC机制的次数),在加载地图等须要用户等待的游戏流程里面主动GC。

     接下来就是跟进3种触发机制作咱们代码上的优化了

  1)、尽可能少new没必要要的字段

 1 object obj = null;
 2 update()
 3 {
 4      object = somebody;
 5 }
 6 
 7 update()
 8 {
 9     object obj =somebody;
10 }

      上面的赋值方式只会在开辟一个内存空间,第二种会反复开辟内存空间,这些空间通常在一代GC里面就会被释放掉。属于最无用的代码方式(不必的  状况下)。

  2).使用对象池

       对象池的使用会大大下降新内存空间的使用,他会在一个内存空间反复给新的值。

       3).尽可能使用缓存机制,少使用Instantiate实例化新对象,由于这里Unity会初始化他身上的组件以及各类序列化的操做,各个物体会根据自身的组件,建立耗时都  不相同

   

       4).字符串的操做

            string的拼接操做是在内部从新new 一个新的出来,由于string在C#是不可变动到,因此在每一次的+= 就至关于new了一个新的字符串出来,若是出现比较频繁   的拼接操做,stringBuilder会比string 更好,可是string在对字符串的操做上会比stringBuider好,至于使用哪种就看具体的需求了。

       5).在地图加载等须要等待的过程当中主动进行GC。

避免内存消耗还有不少的方式,我也是刚刚开始比较全面的学习性能优化,在以上也是我在网上搜集了一些本身能理解的处理方式。

CPU性能管理:

  1、代码层:

     一、 尽可能避免空的Update(),只要写了Update(),无论是否是空的,Unity都会去执行,这里会增长开销

     二、Find  getcomponent 等查找的方法,Unity都会去遍历场景对象和组件,在大型项目中,场景对象一旦变多就会产生很大的开销了,尽可能在start里面调用而不  是update里面反复使用

         三、Update里面尽可能少作遍历,一次UpDate 就会遍历一次,这是一个很大的开销了。

         四、在业务需求不影响的状况下,可让Update里面的逻辑使用计时器,增长间隔,1秒调用一次,2秒调用一次等。

         五、在能够知道触发条件的状况下,尽可能使用委托的方式处理触发效果,而不是一次次的遍历目标的触发状态

         六、和上面同样,尽可能在设计代码的时候,使用观察者模式,理论上来讲,游戏的大部分逻辑均可以使用触发后再执行,特别是UI。(在使用lua热更新的项目      中,大部分的游戏逻辑流程都是经过事件消息的触发来完成的,由于里面没有Uinty那么专业的生命周期)

        七、for 和 foreach 的取舍 :

    在固定长度或长度不须要计算的时候for循环效率高于foreach.

    在不肯定长度,或计算长度有性能损耗的时候,用foreach比较方便

 2、渲染层:

      渲染层的优化包括 图集的结构设计、模型的处理、LOD、mipMap、烘焙等、阴影处理

     图集的结构设计是为了减小额外的draw call,尽可能以模块划分,由于原则上每一个模块之间的UI元素是不会互相耦合的。Unity的texture的大小是根据2的幂来计算到。若是你的图片真实大小是1025,那么他会建立一块2048的texture,也是浪费开销的行为。

模型的处理要结合LOD的使用,在固定视角、固定摄像机深度的游戏中,LOD的发挥效果不是很大,更多的是制做模型的时候就肯定了模型精度

    LOD和MipMap的使用会带来很大的性能提高,可是会受项目影响,具体看项目而定

    烘焙就是在游戏发布以前,场景融合光照提早产生新的贴图,使这个场景不用进行动态光照计算 就能够达到光照的效果,下降了CPU计算的开销,可是对用户的体验确定没有实时光照那么好,通常都是出如今手游中

阴影和烘焙的道理差很少,为了下降实时光照的计算量,能够将阴影设置为假阴影,阴影在是圆的状况,不会产生旋转的变化,同时由于烘焙的缘由,光线没有入射角的变化,也不会产生阴影的投射角度变化,也是在优化性能上比较经常使用的方式

相关文章
相关标签/搜索