在本系列的第一篇文章中,我们用一个项目演示了如何上线微信小游戏平台,这个项目是URP的样例项目,学习价值很高,如果你没看过,请先看这篇文章。
由于目标平台改为微信小游戏平台,项目存在诸多性能消耗问题,如果不调试,将无法在目标平台上正常运行。在开发团队选定项目并开始调试之前,预计可能需要调试以下几个地方:
内存过高,系统崩溃
引擎和项目代码转为 wasm 后,编译运行 wasm 代码需要大约 10 倍于压缩后的 wasm 文件大小,因此剩余的内存空间有限,最小化 wasm 文件后还需要对资源内存和内存进行优化,避免由于纹理压缩格式不合适、资源冗余、变体等导致的内存浪费。
卡顿和掉帧
wasm 代码的执行效率比原生代码慢 3 倍左右,所以原本细小的卡顿在小游戏平台上就会被放大,因此需要对卡顿点进行调试和优化,保证小游戏的流畅运行。
启动时间太长
由于小游戏首次启动时需要从 CDN 下载第一个包,而 wasm 执行效率相较原生 App 较低,导致小游戏启动时间过长。因此需要通过调试找到对启动影响最大的因素并进行优化。
开始调试之前
每个项目在开发过程中都会有很多问题需要解决,但切记不要只凭经验去判断,因为在游戏开发领域,你看到的不一定是事实。最可靠的方法是用软件去调试,只有得到可靠的数据后,才能真正排除问题。
首先我们将平台转换为微信小游戏平台,然后制作调试包。整个开发过程中,要养成定期导出调试报告、分析问题的习惯,避免在最后完成阶段出现无法解决的重大问题。使用和调试时需要检查(注意也要查看微信小游戏打包页面)。
打包包以支持调试
点击打包。打包流程涉及面较广,本期就不一一介绍了。如果对打包流程有疑问,可以参考官方关于打包的视频教程(B站:官方)。
我们用到的第一个调试工具是检查小游戏运行过程中的总内存和总 CPU 占用率。iOS 对小游戏的内存限制比较严格,内存过大会导致游戏运行一段时间后崩溃,一般来说内存需要保持在 1GB 以内才比较安全。CPU 占用率过高会导致手机快速耗电、发热严重,从而触发 CPU 降频,导致游戏帧率下降。
小游戏性能分析工具
iOS -
将正在运行的微信小游戏连接到 Mac 后,打开,选择模板,点击左上角的红点,即可开始录制。一会儿后,就可以看到小游戏的内存使用情况和 CPU 占用情况。
亚行
在设备上运行微信游戏时,可以使用adb命令查看总内存使用情况。需要先打开开发者选项和USB调试,然后连接PC,在命令行中运行以下命令。Pss为当前游戏总内存。
adb shell dumpsys meminfo com.tencent.mm:appbrand1
小游戏总内存主要用于对比分析,例如游戏进行重大更新或者切换引擎版本后,通过对比前后数据,可以确认新版本没有引入其他问题。
打包时勾选,然后在同一个局域网内运行小游戏,就会自动连接,可以实现以下效果:
• 查看各帧的CPU运行时间以及具体的函数调用时间,查找性能热点;
• 检查渲染数量及静态/动态批处理状态;
• 检查每帧的内存使用情况以及GC内存分配和恢复所花费的时间。
每帧的 CPU 时间
呵呵批
内存和 GC
优化CPU性能主要是解决帧率、卡顿、发热等问题,可以让我们对于一些CPU、内存、渲染等有个大概的了解,当需要进一步分析的时候,可以使用以下工具进行深入分析:
• 中央处理器:
○微信打包页面提供了一个-选项,勾选后导入PC后可以在运行时生成性能数据文件,供后续分析使用,具体可参考文档使用CPU性能调优。
• 记忆:
○
○微信封装页面提供了分析底层分配细节的选项,主要是内存分配调用栈
• 渲染:
○
是一款非常好用的小游戏内存优化工具,类似,打包时需要勾选和,在局域网内运行小游戏。
内存分为三类:
• :显存占用,主要为纹理、模型等。当这部分过高时,需要检查是否有未释放的纹理,以及纹理大小和压缩格式是否合适。
• :引擎和资源的内存使用情况。加载过多资源、AB 或过多 C# 代码(VM 内存消耗)可能会导致此内存使用率过高。
• :C#代码中的内存使用情况,主要是数组、字典等数据结构的内存使用情况。
若内存占用过高,可以查看右侧详细信息确认资源设置(可读写、压缩格式等)是否正确。
在页面中,可以通过按照资源名称或者大小排序的方式,快速找到重复冗余的资源,通过对比右侧的引用关系,可以分析出冗余的原因。比如下图中两张重复的 TMP 贴图,一张来自 AB,一张来自场景。而 AB 中的场景和 UI 都引用了同一个 TMP 字体资源,因此这个冗余问题可以通过调整打包结构来解决。
引擎在微信小游戏平台支持该功能,当游戏渲染失败或者GPU没有达到预期效果时,可以通过该功能查看原因。
例如,如果两个使用相同物料的物料被包装到不同的AB中,则从AB加载后该批次将无效。使用该功能时,在这里会看到提示“使用了不同的物料”。原因是包装AB时没有指定包装的物料,导致每个AB中都有一个物料实例。
调试有多重要?
调试很重要,但这是大多数开发团队在开发后期才会做的事情,熟悉调试工具也是一门职业。小型开发团队通常人手不足,没有调试流程,往往在开发过程中甚至游戏发布前都无法找到项目卡顿或崩溃的原因。即使游戏内容很好,也可能发布后崩溃,问题无法解决,导致项目失败。如果从开发前期或中期就一直有一个调试流程,就像是定时健康检查,当项目出现问题时就能更快做出反应。
调试过程中,也可以解决误判的问题,我们可以用几个情境模拟来理解:
情境模拟1
在一款 2D 放置类游戏中,测试人员发现每次战斗场景中怪物数量过多,游戏就会有卡顿感。程序员测试发现,当怪物数量超过 20 只时,帧率就会开始下降。程序员在会议上确定是怪物网格数量过多导致的。由于上线在即,美术人员又不能降低所有怪物的标准。项目经理最终决定将战斗怪物数量的上限锁定在 20 只,这最终牺牲了战斗的刺激感。
事实:从 GPU 的实时监控中,我们知道从战斗开始到战斗结束,整个屏幕都在不断重绘。这期间,当场上怪物数量达到 20 个左右时,GPU 的绘制压力就达到了 100%,导致帧率开始下降。最后发现,战斗结束时会施放一个全屏的烟花动画。这个动画一开始是为了方便播放而加载到屏幕上的,第一帧是完全透明的,所以没人注意到这个动画的存在。全屏透明的图片导致每一帧都要重绘整个屏幕,从而导致性能问题。排除这个烟花动画就可以解决问题。
情境模拟 2
3D动作冒险手游,美术质量标准高,场景精美,需要保持原有的帧率,但真机测试只能在除最高端手机外的所有手机上实现,手机容易发热耗电。会上,项目经理希望保持美术质量标准,于是要求程序组精简场景上运行的所有代码。最终,程序组花了1个半月的时间,将底层完全导入,并将工作分为多个工作线程,才达到标准。
事实:根据 和 的报告,很多场景物体没有被遮挡剔除()排除,导致很多模型虽然看不清却被渲染出来了。原因是场景物体的设计有很多漏洞。在调整遮挡剔除设置()后,艺术家们也修正了模型设计并导入。最终结果比之前更好。
情境模拟 3
这是一款2D卡牌游戏,开发团队以非常常规的方式开发游戏,所有开发标准都很宽松,比如加载时间不能超过10秒,游戏运行在30帧,不能有任何卡顿,因此整个项目直到开发结束都没有出现什么特别的问题,已经可以上线了。
事实:从数据中我们可以看到,初始加载的性能图呈现出 U 型,也就是说如果加载耗时 10 秒,那么只有第 1 秒和第 10 秒压力较大,另外 8 秒因为加载的物体很小,在等待下一帧,所以加载得比较早。判断重新均匀分配 AB 的大小可以改善这个问题,但最终开发团队决定写代码判断加载完 AB 后是否还有时间,再继续加载下一个包。最终,加载时间从原来的 10 秒缩减到了 5 秒。
另外我们还看到每次打开不同的菜单UI,都有1秒的激活时间。程序组表示不知道为什么不能立即打开,但项目经理也能接受就这么算了。最后我们发现原因是每个UI在打开时都设置为激活状态,关闭时又改为禁用状态,导致每次打开和关闭UI时都会有性能消耗。最后开发团队将所有UI都设置在很远的坐标处并排列整齐,并设置相同的Z轴,保证所有UI渲染都是同一批渲染的。在打开不同的UI时,只要将该UI使用的相机移到该UI上,这样系统就会自动移除不在相机范围内的UI渲染。虽然内存消耗增加了,但既能达到立即打开UI的效果,又能提高性能。
从这些案例中,你是否能体会到文章开头提到的“眼见不一定为实”对开发的影响呢?它不仅影响项目质量、发布进度压力,甚至会引发美术和程序员之间的矛盾。这也是每个项目经理需要了解清楚的开发环节。
觉得调试很难?这里有在线调试报告服务,只要安装指定套件,打包上传到官方UPR服务,就能生成检测报告!
UPR——专业性能优化工具: