我是靠谱客的博主 搞怪大地,最近开发中收集的这篇文章主要介绍instantiate 卡顿严重_Unity3D_记一次CPU卡顿的排查实践,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

这是一次CPU卡顿的排查实践,开发环境是Unity5.3.4p5 + uGUI

======

为了避免打log引起的额外消耗,所以以下分析基于log关闭后的Profiler数据

Debug.logger.logEnabled =false;

问题1:ConfigUtil.Get().Single(Func)

List  ConfigUtil.Get()内含List.AddRange()申请临时内存,相对GC Alloc和耗时较多;

T  List.Single(Func)多次遍历查找同一个List,耗时较多。影响范围较广。

修行状态的红点计算NinjaPracticeController.UpdatePracticeState()较为复杂,查询修行配置有多层循环嵌套,而且内层嵌套有多次重复计算,且频繁出现于回包中。比如心跳回包会计算修行红点状态,其他一些回包触发OnSyncSthChangeCommand的也会引起修行红点计算。

修改前(60次+60次):

image001.1471070551.jpg

image002.1471070551.png

image003.1471070552.jpg

将查询全量配置提前到for循环之前算好。并且classEvolveCfg和classUpgradeCfg这两项配置信息并不总是需要,而是根据底下if-else的条件局部需要,所以挪到实际需要的地方才计算。

修改后(40次+3次):

image004.1471070552.jpg

Single方法的调用还可以进一步优化(配置List转换为Map,然后for循环内按Key查找)。

更新忍者状态的NinjaController.UpdateNinjaState也有类似的现象:

image005.1471070552.png

初次加载忍者技能、忍者课程修炼也是如此:

image006.1471070552.png

image007.1471070552.png

其他模块的List  ConfigUtil.Get()调用,建议按需修改。

问题2:MaouOutline的数组重置操作

为达到更佳的描边效果,重写了ModifyMesh/ModifyVertices的实现,而MaouOutline脚本又频繁出现在各个界面。影响范围较广。

修改前:

image008.1471070552.png

image009.1471070552.png

发现主要消耗是在重设数组长度。将vertexs数组初始化时指定初始长度,性能可小幅度提升。

经实测,List vertexs =newList(256);

指定初始长度为256,比128或512或其他都好一丢丢(减少了SetCapacity(Array.Resize)的消耗,但同时增加了List构造函数的消耗)。

第一次修改后:

image010.1471070552.png

进一步修改,调整为静态全局数组,就不会每次都重置数组长度了:

image011.1471070552.png

第二次修改后:

image012.1471070552.png

MaouOutline的ModifyMesh/ModifyVertices已经没问题了,但是Unity自带的Outline的ModifyMesh仍然有重置数组长度的现象。

经排查,发现TaskItem有两个按钮Text使用了Outline而非MaouOutline。于是将所涉及prefab的Outline脚本全部替换成MaouOutline脚本即可。

Outline替换为MaouOutline后:

image013.1471070553.png

到此GC Alloc基本解决了(0.9M=>22K)。

但进一步又发现,剩余的耗时问题集中到了ModifyVertices(每次ModifyVertices调用都会触发8次ApplyShadow调用),此问题待解决。

问题3:GameObject.SetActive(ture/false)引起的毛刺,即使并没有实际改变true/false的状态,也会有额外的消耗。

建议封装一个静态方法:先判断GameObject.activeSelf当前状态,然后再作GameObject.SetActive(ture/false)修改状态。

对于在业务View初始化方法中只作一次GameObject状态初始化的,可以不做修改。

对于操作时会变更状态的(比如赌小游戏滚动前后的按钮状态切换、奖励展示切换),建议增加判断。

已封装为UIUtil.SetActive(GameObjectgo, bool v),可直接使用。

修改前:

image014.1471070553.png

修改后:

image015.1471070553.png

赌小游戏已修改,其他模块可按需修改。

比如排行榜的一个条目:

image016.1471070553.png

问题4:B.GetView=>B.OnShow=>A.OnHide

界面切换会有新界面(B)的GetView和OnShow,以及旧界面(A)的OnHide,而这里的多次SetActive(true/false)会引发多个脚本OnEnable/OnDisable。

现象:

image017.1471070553.png

一次SetActive(true/false)会引发上百次的OnEnable/OnDisable:

image018.1471070553.png

image019.1471070553.png

两个建议:

(1)对于Instantiate创建的VIew,无需默认设为SetActive(false),因为马上就OnShow=> SetActive(true)了。

image020.1471070553.png

(2)对于需要频繁显示和隐藏的常驻VIew(比如TitleBar之类的),OnShow和OnHide中除了使用SetActive(true/false)外,也可考虑position移入移出屏幕,或者设置Scale为1或0等等。

但是需要注意,应该增加忽略隐藏状态下业务逻辑的代码。

image021.1471070553.png

问题5:可疑的Graphic.Rebuild=>Text.OnPopulateMesh=>Font.CacheFontForText

image022.1471070553.png

初始化或更换Text.text的文本,会引发Text.OnPopulateMesh,有时还会引起Font.CacheFontForText=>TextUpdateGeometry(耗时)和Text.cachedTextGenerator(GC Alloc)。

Image也有类似现象。优化方法待思考。

问题6:可疑的Tx.OnUpdate

这里的大毛刺使得战斗开场那一帧比较卡,看到界面显示一个空的战斗场地,等一两秒后才有人物跳出来。

由于Profiler信息量太大,无法使用DeepProfiler查看详情。

通过添加Profiler代码定位,最后定位到Tx.OnUpdate()里的tx_object_unity_update();,然后线索就断了。

真实原因待查。

image023.1471070554.png

添加了Profiler辅助方法:

image024.1471070554.png

其中加载了许多图标,包括忍者头像、战斗上阵的人物等。如果原因是资源尺寸过大,可考虑能否裁剪成多张小尺寸的。

image025.1471070554.png

image026.1471070554.png

问题7:可疑的Text. preferredWidth

image027.1471070554.png

在普通副本和精英副本切换时,发现有一个可疑的Text. preferredWidth,它会触发Text.cachedTextGeneratorForLayout,从Profiler看似乎是申请了一个长度较大的List。

经走读代码发现该行代码实际是不需要的,于是直接注释掉。

另全量搜索发现其他脚本也多处出现Text. preferredWidth,还需逐一排查。

image028.1471070554.png

问题8:可疑的Component.GetComponentFastPath

进入某些列表界面(比如任务界面),初始化MaouGrid组件时会调用SetParent。

而SetParent会触发一些Unity自有脚本(比如MaskableGraphic)的OnEnable/OnDisable的成倍调用,耗时和GC Alloc累积起来也比较可观。

切换SetActive(true/false)也有类似现象。

image029.1471070554.png

展开MaskableGraphic.OnEnable/OnDisable,最后落到Component.GetComponentFastPath,此方法耗时和GCAlloc原因待查。

问题9:debug信息输出导致的额外损耗

VersionView每一帧Update()都在刷新帧率,导致过渡频繁的字符串Format和Concat

建议修改为StringBuilder,而固定字符串(版本信息字符串、网络状态字符串)可改为分别用单独的UI.Text显示,每次只刷新变化的数据(比如帧率)。

(优先级较低,暂时可忽略,且正式版本会屏蔽)

image030.1471070554.png

另一个可疑的debug信息(PrettifyProto.ToStr和LogUtil.WritePre),常见于一些回包中,也可以考虑处理一下:

image031.1471070554.png

问题10:界面加载和界面刷新时的耗时

界面加载时有较多的资源加载。比如通灵兽界面:

image032.1471070554.png

image033.1471070554.png

又比如任务界面:

image034.1471070555.png

领取任务奖励后,任务条目更新又有一些耗时的刷新操作:

image035.1471070555.png

经分析,这里每次都会先Hide(全部),然后Show(其中某几个),可考虑优化。

问题11:切换普通副本和精英副本,会有瞬间的白屏

image036.1471070555.png

image037.1471070555.jpg

问题12:图标加载时有额外的字符串操作消耗。

比如副本介绍界面的奖励图标加载(除了字符串操作,还有一个可疑的IdUtil.TryGetId):

image038.1471070555.png

或者任务条目的奖励图标查询(除了字符串操作,还有一个可疑的Behaviour.set_enabled):

image039.1471070555.png

最后

以上就是搞怪大地为你收集整理的instantiate 卡顿严重_Unity3D_记一次CPU卡顿的排查实践的全部内容,希望文章能够帮你解决instantiate 卡顿严重_Unity3D_记一次CPU卡顿的排查实践所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部