9.3 性能诊断与优化


9.3 性能诊断与优化

本节摘要:性能优化的第一律是先测量后动手——监视器看总量曲线、剖析器看函数耗时、绘制统计看渲染压力,三者构成完整仪表盘。优化行动有正确次序:先降频率再降成本,先减对象再减调用,先查算法再换语言。本节讲三件工具的读法与一份优化行动清单。

一个残忍的事实先摆出来:开发者关于"哪里慢"的直觉,错误率惊人。最常见的误判方向是想当然怀疑语言慢(第 4 章)、怀疑引擎慢,而真凶往往是"每帧做了一件不该每帧做的事"。所以本章第一律只有四个字:先测后动。没有剖析报告支撑的优化,十次里九次是在优化不存在的问题。

仪表盘三件套

监视器是仪表盘的总量表:帧率、帧时间、内存、对象数、绘制调用数,运行时实时曲线。它的价值是"发现异常"——曲线爬升(泄漏)、锯齿抖动(周期性卡顿)、台阶跳变(某事件触发)。定位不到具体函数,但圈定问题类别。

剖析器是放大镜:逐帧记录每个函数的调用次数与耗时,按占比排序。用法是"复现卡顿、停止录制、看榜首"——独占时间最高的函数就是嫌疑人。它还能显示物理步进、渲染准备等引擎阶段的耗时分布,帧预算的去向一目了然。

渲染统计是渲染专档:绘制调用次数、顶点数、显存占用。其中绘制调用次数是 2D 与 3D 共同的关键指标——每次"换一批材质画一批东西"就是一次调用,调用次数比顶点总数更早成为瓶颈(处理器要为每次调用付固定开销)。

# 自测工具:把帧时间写进标签 肉眼监控 func _process(delta: float) -> void: var ft := Performance.get_monitor(Performance.TIME_PROCESS) * 1000.0 var fps := Engine.get_frames_per_second() %Stat.text = "帧时 %.1f 毫秒 帧率 %d" % [ft, fps]

优化行动的正确次序

诊断出问题后,行动要按"性价比从高到低"的次序执行。这张次序表是本节的核心资产:

**第一层:降频率。**这段代码必须每帧跑吗?降到每几百毫秒一次(远处敌人的人工智能降频采样)、降到事件触发时(界面刷新只在数据变化时)、降到不可见时停(屏幕外实体休眠)。频率除以十,成本除以十——数学最诚实的优化。

**第二层:减对象。**每帧实例化的东西改成对象池复用(子弹、特效、伤害数字):预建一批、轮流使用、用完归还。第 2 章的销毁成本与第 8 章的加载成本在这里一并省下。

**第三层:查算法与数据结构。**循环里找节点的改成缓存引用;每帧排序的改成插入时维护;线性查找的换成字典或组。这一层的收益经常是数量级的,且不依赖任何引擎特性。

**第四层:批渲染。**绘制调用高时的专用解法:图集合并(同一张图的精灵合并成一次调用)、多层瓦片合并、相同材质的网格合一。2D 项目里"把散图拼进图集"常常是免费的大额提速。

**第五层:换语言换轨道。**纯计算热区迁 C# 或原生扩展(第 4 章三轨道)。走到这一步的项目是少数,走到前的每一层都更便宜。

⚠️ 常见坑:优化做成"到处都是微优化"——每个函数抠一点语法糖,帧率纹丝不动。微优化的问题不在错,在量级:解释执行的语言里省一次属性访问,省的是纳秒;一次错误的每帧重算,费的是毫秒。盯大头,是性能工程的美德。

卡顿类问题的专项排查

"平均帧率正常但偶尔卡一下"是另一类问题,排查思路不同。三个高频病因:加载卡顿(运行中同步加载大资源,改为预载或后台加载,第 8 章流式策略);实例化风暴(一次性生成大量节点,改为分帧生成或对象池);垃圾与清理风暴(同一帧销毁大量对象,排队销毁天然分批,或主动分帧)。卡顿的通用解法是把大事拆成小事分帧做——每帧做一小片,任何一帧都不超支。

# 分帧生成:每帧最多两个 波次生成不卡顿 var _pending: Array[PackedScene] = [] func _process(_delta: float) -> void: for i in mini(2, _pending.size()): add_child(_pending.pop_front().instantiate()) if _pending.is_empty(): set_process(false) # 没活就关掉处理回调

一个真实的优化案例走查

把方法论装进一个案例。症状:深井矿工后期关卡帧率从六十掉到三十。第一步剖析器定位——榜首是矿石管理脚本的每帧扫描,它遍历全场两百多枚矿石更新闪光动画。第二步看行动五层次:这属于"降频率"层——闪光是视觉效果,不需要每帧扫描,改成每个矿石自己的动画播放器循环播放(引擎内部处理,脚本零参与),脚本扫描整个删掉。一次修改,帧率回到六十。

案例的教训有两条。其一,榜首函数本身就是"管理器每帧扫描"这类模式——凡是"每帧遍历全部子物体"的代码都值得先怀疑,几乎总有更高频责任下放的写法(动画交给动画系统、移动交给物理、状态变化交给信号)。其二,修完必须复测:剖析器再跑一遍,确认榜首换人,而不是"感觉流畅了"——感觉会撒谎,曲线不会。

目标导向的预算管理

优化的终点不是"最快"而是"够稳":定目标帧率(六十或三十),换算成帧预算(约十六点七或三十三点三毫秒),把预算分给各系统(物理几毫秒、逻辑几毫秒、渲染留多少),监视器上看曲线贴着预算走。预算思维的好处是把"优化"从无尽的艺术变成可验收的工程:达标即停,把时间还给玩法。移动端另有一条铁律:拿真机测——开发机的性能曲线与中端手机毫无关系,模拟器更不能算数(第 10 章导出后的真机回归是发布必过项)。

图 1 性能问题的定位与行动地图

图 1 性能问题的定位与行动地图

本节要点回顾

  • 先测后动:直觉找瓶颈的错误率惊人,剖析报告是行动的通行证
  • 三件套分工:监视器看总量、剖析器看函数、渲染统计看绘制调用
  • 五层次次序:降频率、减对象、查算法、批渲染、换轨道——由便宜到昂贵
  • 卡顿专项:三大风暴(加载、实例化、清理),通用解法是分帧做小事
  • 预算思维:帧率换预算、预算分系统、达标即停
  • 移动端铁律:真机测试,开发机与模拟器都不算数

诊断与优化的方法论齐了。下一章是最后一程:把打磨好的游戏导出到所有平台,并看看引擎生态里还有什么等你取用。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U