性能优化 ②

CPU的方面的优化:

CPU优化方向:

1、DrawCalls

2、物理组件(Physics)

3、GC(GC为处理内存,此项为CPU使用GC处理内存时产生的性能损耗)

4、程序代码

Drawcalls:

Drawcall是啥?其实就是对底层图形程序(比如:OpenGL ES)接口的调用,以在屏幕上画出东西。

1)使用Draw Call Batching,也就是描绘调用批处理。Unity在运行时可以将一些物体进行合并,从而用一个描绘调用来渲染他们。

静态批处理Static Batching,只要是静态不动的物体且具有相同材质的话就可以使用静态批处理来降低描绘调用(注:shader不同则会增加纹理的拼合降低渲染效率)

动态批处理Dynamic Batching:动态批处理是引擎自动进行,无需设置,当物体共享相同的材质,则引擎就会自动对Drawcall进行优化,也就是动态批处理(如实例化预制件)。动态批处理存在约束,稍有不慎就会增加Drawcall

动态批处理的约束:

1、批处理动态物体需要在每个顶点上进行一定的开销,所以动态批处理仅支持小于900顶点的网格物体。

2、如果你的着色器使用顶点位置,法线和UV值三种属性,那么你只能批处理300顶点以下的物体;如果你的着色器需要使用顶点位置,法线,UV0,UV1和切向量,那你只能批处理180顶点以下的物体。

3、不要使用缩放。分别拥有缩放大小(1,1,1) 和(2,2,2)的两个物体将不会进行批处理。

4、统一缩放的物体不会与非统一缩放的物体进行批处理。

5、使用缩放尺度(1,1,1) 和 (1,2,1)的两个物体将不会进行批处理,但是使用缩放尺度(1,2,1) 和(1,3,1)的两个物体将可以进行批处理。

6、使用不同材质的实例化物体(instance)将会导致批处理失败。

7、拥有lightmap的物体含有额外(隐藏)的材质属性,比如:lightmap的偏移和缩放系数等。所以,拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一部分)。

8、多通道的shader会妨碍批处理操作。比如,几乎unity中所有的着色器在前向渲染中都支持多个光源,并为它们有效地开辟多个通道。

9、预设体的实例会自动地使用相同的网格模型和材质。

所以尽量使用静态批处理。

2)NGUI和UGUI需将同一界面的UI元素打包图集。

物理组件:

1)设置Fixed timestep,减少物理计算次数,提高游戏性能。

2)减少FPS,在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS=60,EverySecondVBlank = 30;这两种情况都不符合游戏的FPS的话,我们需要手动调整FPS,首先关闭垂直同步这个功能,然后在代码的Awake方法里手动设置FPS(Application.targetFrameRate = 45;)

降低FPS的好处:

1.省电,减少手机发热的情况;

2.能都稳定游戏FPS,减少出现卡顿的情况。

关于垂直同步:

什么是垂直同步,简单来说就是显示器上的所有图像都是一线一线扫描上去的,显示器都有两种同步参数,水平和垂直同步,水平同步信号决定画出一条屏幕横线的时间,垂直决定从屏幕顶部画一条线到底部,再返回原位置的时间,垂直同步决定了显示器的刷新水平,如果选择了等待同步信号,但是比较强的显卡会迅速绘制完一屏的图像,但是没有垂直同步信号的到达,显示器无法绘制下一屏,所以操作系统刷新率会制约FPS,如果选择不等待,即关闭垂直同步,那就会提升性能,发挥显卡的最大性能,但是有个弊端,就是正是因为垂直同步的存在才使得游戏进程和显示器刷新率同步,使得画面变得更加平滑和稳定。因此是否关闭垂直同步提升帧数需要酌情考虑。

3)尽量不用MeshCollider

如果可以的话,尽量不用MeshCollider,以节省不必要的开销。如果不能避免的话,尽量用减少Mesh的面片数,或用较少面片的代理体来代替。

4)粒子组件,屏幕上最大粒子数量建议小于200个,粒子应尽可能的小,关闭粒子的碰撞功能。

GC:

虽然GC是用来处理内存的,但是却会增加CPU的开销,首先我们要明确所谓的GC是Mono运行时的机制,而非引擎的机制,所以GC也主要是针对Mono的对象来说的,而它管理的也是Mono的托管堆。 搞清楚这一点,你也就明白了GC不是用来处理引擎的assets(纹理啦,音效啦等等)的内存释放的,因为U3D引擎也有自己的内存堆而不是和Mono一起使用所谓的托管堆。其次我们要搞清楚什么东西会被分配到托管堆上?不错咯,就是引用类型咯。比如类的实例,字符串,数组等等。而作为int,float,包括结构体struct其实都是值类型,它们会被分配在堆栈上而非堆上。所以我们关注的对象无外乎就是类实例,字符串,数组这些了。所以GC的优化说白了也就是代码的优化。

此部分的代码优化只针对是否会触发GC:

1)字符串处理。如频繁操作单个字符串使用StringBuilder

2)尽量不要使用foreach,而是使用for。foreach其实会涉及到迭代器的使用,而据传说每一次循环所产生的迭代器会带来24 Bytes的垃圾。那么循环10次就是240Bytes。

3)不要直接访问gameobject的tag属性。比如if (go.tag == “human”)最好换成if (go.CompareTag (“human”))。因为访问物体的tag属性会在堆上额外的分配空间。如果在循环中这么处理,留下的垃圾就可想而知了。

4)使用“池”,以实现空间的重复利用。

5)最好不用LINQ的命令,因为它们会分配临时的空间,同样也是GC收集的目标。

代码:

1)不要频繁使用GetComponent去频繁获取组件,如使用可在Awake函数中持有引用。

2)善于使用OnBecameVisible()和OnBecameVisible()来控制物体的Update()函数的执行以减少开销。

3)使用内建数组如使用Vector3.zero而不是new Vector(0,0,0)(减少new的使用);

4)数组、集合类元素优先使用Array,其次是List;

5)脚本在不使用时脚本禁用之,需要时再启用;

6)可以使用Ray来代替OnMouseXXX类方法

7)尽量少用模运算和除法运算,比如a/5f,一定要写成a*0.2f

8)不要使用原生的GUI方法

你可能感兴趣的:(性能优化 ②)