Skip to content

路线 A|Cocos 引擎、渲染与性能 ​

A3|Advanced Performance:CPU、GPU、内存与帧稳定性 ​

适用基础: A1、A2、Stage05、Stage07 目标: 建立可复现、可量化、可回归的系统性能分析能力。


一、从“卡”改成指标 ​

text
FPS:频率
Frame Time:单帧耗时
CPU/GPU:主导瓶颈
Memory:常驻、峰值、碎片和泄漏
IO:加载、解码、上传和写盘

60 FPS 的预算约 16.67 ms,不能把 CPU、GPU、脚本和余量都各自花满。帧稳定性还要看 P95/P99 和长帧,而不只是平均值。

二、证据链 ​

text
现象 → 固定场景 → 记录基线 → 定位维度 → 最小修改
→ 重测同一指标 → 真实设备回归 → 保留报告

性能分析的第一步不是优化,而是建立可比较的基线:同一版本、设备、分辨率、场景、操作和缓存条件下,分别记录平均值、P95/P99、长帧、峰值内存和稳定值。冷启动、热启动、战斗峰值和场景切换属于不同工作负载,不能混成一条 FPS 曲线。

三、CPU Cache 与数据组织 ​

连续数组、SoA、减少指针跳转和避免热路径临时对象通常比“换一个容器名字”更重要。使用 Native profiler 和采样火焰图确认热点,不能凭代码长度判断耗时。

Cache line 会把相邻字节一起带入缓存,因此顺序遍历通常比随机指针追踪更友好。AoS 便于处理完整对象,SoA 便于只扫描少量热字段;真正选择取决于每帧访问模式。Branch Prediction 依赖分支规律,杂乱对象类型和不可预测状态会让流水线频繁清空,但只有在采样热点中出现时才值得改写数据布局。

四、内存分配与碎片 ​

高频 new/delete 会增加 allocator、锁、碎片和 GC/JSB 交互成本。对象池只有在生命周期和复位协议清晰时才有价值;池过大、复位遗漏和长期持有也会制造内存问题。

对象池的收益来自减少分配和初始化,但代价是池内对象常驻、复位逻辑复杂、事件/Timer 残留和峰值容量。判断是否值得使用,要同时比较分配次数、GC、CPU、内存峰值、稳定值和复位错误;不能因为“创建次数下降”就判定优化成功。

通用 allocator 服务不同大小和生命周期的对象,容易产生元数据、锁和碎片成本。Arena 把同一阶段对象集中分配并整体释放,Memory Pool 固定或分级管理可复用块;它们通过限制生命周期模型换取效率。若对象释放顺序不可控、跨线程或必须单独析构,专用分配器的复杂度会明显上升。

五、CPU/GPU 同步 ​

读回 GPU、等待纹理上传、强制 flush 或提交后立即查询结果,都可能把异步流水线变成同步等待。Frame pacing 还受平台刷新率、VSync 和后台策略影响。

CPU 和 GPU 通常流水工作:CPU 准备后续帧时 GPU 仍执行之前命令。同步读回、资源覆写或缓冲不足会迫使一方等待另一方。平均 60 FPS 仍可能因帧间隔不均匀产生卡顿,因此 Frame Pacing 要看 present 间隔、队列深度和长帧分布,而不只是总吞吐。

六、多线程与 Job System ​

后台适合纯数据、解码和批处理,不能直接改 Node/Renderer/脚本。锁竞争、false sharing、任务过细和主线程合并成本会抵消收益。先定义所有权和完成点,再设计线程。

False Sharing 指不同线程写入同一 cache line 内的不同字段,虽然没有逻辑共享,缓存一致性仍会让整行反复迁移。Job System 通常把任务分解、依赖计数和 worker 队列结合起来;任务只有在输入不可变、输出 owner 清楚并且粒度足够时才能扩展。主线程最终合并结果仍属于帧预算。

七、启动与加载 ​

把首屏拆成启动、脚本初始化、场景反序列化、纹理解码、上传、首帧渲染。分阶段加载不是把所有工作搬到后台,而是控制关键路径和峰值。

八、Native Crash 与性能回归 ​

任何优化都要同时记录正确性、内存、CPU、GPU、设备和版本。Native crash 必须保留符号化堆栈、构建 commit、设备信息和复现步骤;“更快但偶发崩溃”不是优化。

九、性能问题的知识化拆解 ​

把一个性能问题拆成四个问题:

text
哪一个资源超预算?
它属于 CPU、GPU、Memory 还是 IO?
哪个调用或数据结构制造了成本?
修改后成本是否转移到别的维度?

CPU 热点看采样栈和调用次数,GPU 热点看分辨率/overdraw/Shader 对照,内存问题看对象引用和分配轨迹,IO 问题看等待时间和峰值。四类证据不能互相替代。

十、常见错误方案 ​

text
只看平均 FPS:忽略长帧
先优化最显眼代码:没有热点证据
只在编辑器测:设备和构建模式不同
对象池越大越好:常驻内存和复位成本上升
DrawCall 越低越好:可能换来更高 overdraw 或 Shader 成本

十一、练习与答案 ​

1. CPU 只有 8 ms,为什么仍然掉帧? ​

GPU、提交同步、VSync、平台调度或长帧分布可能超过预算;必须同时看 GPU 和 frame pacing。

2. 如何判断对象池是否有效? ​

比较同一场景下分配次数、GC、CPU、内存峰值、稳定值和复位错误;只看创建次数减少不够。

3. 优化报告最少包含什么? ​

版本、设备、场景、操作、基线、修改、指标、统计方法、正确性和回滚条件。

十二、阶段输出 ​

完成 A3 后应能提交一份可复现性能报告,并把指标接入回归检查,而不是只给出“优化后感觉更流畅”。