抛砖引例
有别于之前家喻户晓的畅销大作,这次我们拿一个普通小清晰RPG游戏作为案例。在我们测试过的大量项目中,该游戏是少见的,以UI性能上位的。虽然这仅仅是第一次测试的数据,但是其在CPU耗时、堆内存分配上的表现都是甚如人意,瑕不掩瑜。
在UWA的报告中打开UI模块性能界面,大家就能看到如上图UI相关的详细参数。包括:CPU峰值、CPU均值、堆内存分配总值、堆内存分配均值。这里的CPU峰值取自以下4个UI函数的耗时总和。堆内存分配总值指测试过程中,这4个UI性能函数分配的堆内存之和。
UICamera.Update()
该函数通常在点击时出现开销。因此,当该函数的CPU开销较高时,通常都是因为调用了其他的较为耗时的函数引起。
UIRect.Update()
该函数通常在需要更新锚点位置时出现开销。因此,当该函数的CPU开销持续较高时,通常是因为当前场景中有较多的UI元素绑定了OnUpdate模式的锚点。
UIPanel.LateUpdate()
该函数为NGUI最主要的CPU开销,包含了对所有UI界面包括其下UI元素的状态更新、网格重建、DrawCall合并等操作。大量的UI变动或者不合理的UIPanel布局都有可能导致该函数出现较高的峰值。
UIRect.Start()
该函数主要涉及到UI元素的初始化操作,通常在UI界面被实例化时出现并产生一定的CPU开销。
报告往下看,是各个函数的具体CPU和堆内存开销。如果你对这些数据代表的数字是一脸懵逼的状态,不清楚是偏高了还是偏低了,请先打开右边的分析与建议。
如下图,红框内分别给出了四个函数的CPU占用详情,包括主体范围是多少,过高或过低。一般来说,我们建议堆内存总值控制在30MB内,如果可以,尽量再往20MB的极限靠靠。
在此,我们不妨点击某一帧,在底部查看该帧的CPU耗时。
上图中显示,在第5500帧时CPU的耗时为5.4ms,若要溯本求源,我们可以再去CPU耗时详情中定位是哪个函数引起的CPU开销。
如上图,我们看到这些耗时分别为:
UICamera.Update(): 1.2 ms
UIRect.Update(): 0.2 ms
UIPanel.LateUpdate(): 4.0 ms
UIRect.Start(): 0.0 ms (由于四舍五入)
通过这些具体的性能函数,以及这些函数的意义我们就可以大致做一个判断了。接下来就需要各位程序大大结合自己的UI设计具体问题具体分析了。由于此文的目的是为了帮助大家理解UWA性能优化报告,因而并不会大篇幅讲解NGUI性能优化的细则,下文先给一些比较通用的建议,可谓优化中的黄金法则!
优化支招
1、 尽可能将静态UI元素和频繁变化的动态UI元素分开,存放于不同的Panel下。同时,对于不同频率的动态元素也建议存放于不同的Panel中。
2、对于UI元素,OnEnable和OnDisable都会进行较多的操作,因此即使不涉及到资源的加载,依然会有较大的CPU开销,因此,对于切换非常频繁的UI界面,我们建议更高效的做法是:
(1)改变UI的位置(以UIPanel为单位)来实现UI的隐藏和显示,因为是位置移动,所以并不产生多余的CPU消耗,同时又可以节省Enable和Disable的CPU开销。
(2) 通过设置相机的Culling mask 来实现 UI 界面的隐藏和显示,同样避免Enable/Disable操作。该做法可能会一定程度地提高内存的开销(UIDrawCall中存储的Mesh),因此可以根据UI切换的频率来决定是否要进行优化。
3、UI资源进行详细检测,查看其分辨率、格式等是否足够精简和优化。
今天的分享就到这里,下一期我们会继续讲解UWA测评报告中的内存模块,感谢各位开发者的关注。