跳到主要内容

性能优化-PR全流程

流程速览

  • 工具层:Unity(Profiler / Frame Debugger / Memory Profiler / Overdraw)+ 平台工具(如 Xcode/Metal)+ 脚本侧(Lua Profiler)+ 项目级回归(UPR/自动化报告)
  • 指标层:内存 / CPU / GPU(按“要采集 → 常见信号 → 常用抓手”组织)
  • 流程层:复现 → 基线 → 定位 → 方案 → 实现 → 对比 → 回归 → PR 报告 → 监控与回滚

工具汇总

unity 内部工具使用

Profiler

Profiler是我们排查性能问题最常用的工具,可帮我们排查性能问题原因 Profiler使用教程:https://zhanglan.pages.dev/blog/unity_profiler_usage

FrameDebugger

Frame Debugger 主要用于排查 渲染顺序、Pass/Draw Call 组成、合批情况、材质/关键字切换 等问题。

常见情况:

  1. 版本打到真机上,有渲染粉色(Shader 丢失/变体缺失/材质引用异常)
  2. 调试游戏对象渲染 Shader 的变量值 FrameDebugger使用教程:https://zhanglan.pages.dev/blog/unity-frame-debugger

Memory Profiler

用于查看 内存占用大头(Top Allocations)、定位 未释放引用链、排查 内存泄漏/驻留不回落

Memory Profiler使用教程 :https://zhanglan.pages.dev/blog/unity_memory_profiler

OverDraw

主要查看渲染相关的 屏幕填充率 以及 重复绘制率(尤其是 UI、透明特效、雾/云等)。 OverDraw使用教程:https://zhanglan.pages.dev/blog/rendering-debug-overdraw

Xcode

主要用于定位 移动端 GPU 瓶颈(如 GPU Frame Capture / Metal System Trace),辅助判断:

  • 主要渲染阶段开销(Tile/Fragment/Compute 等)
  • Render Pass / 纹理带宽 / 过度绘制(Overdraw)倾向
  • 分辨率、后处理、透明叠加带来的 Fillrate Pressure

SLua

用于定位 Lua 脚本侧的 CPU 热点内存分配调用栈 等.

SLua Profiler使用教程: https://github.com/Tencent/sluaunreal/wiki/slua-Profiler-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E/aaee3a8e742aff3be3aa8602f2739e11f5295a8e

可用排查Lua的性能问题

UPR

UPR 可理解为“项目级性能体检与回归系统”:

  • 统一跑固定 Case(场景/战斗/主城/加载)
  • 采集核心指标(FPS、CPU/GPU Frame、内存峰值/回落、GC、加载尖刺)
  • 生成对比报告(版本间/分支间),用于快速发现回归点并定位责任模块

性能优化流程

注意事项(保证数据可信)

  • 固定变量:同一机型、同一画质档、同一分辨率/渲染比例、同一场景与操作路径、同一构建配置(尽量统一 Development/Release 口径)。
  • 采样规范
    • 尖刺问题:至少抓到 尖刺前后 3–5 秒 的 Timeline(必要时加自定义 Marker/埋点)。
    • 稳态问题:持续运行 30–120 秒,避免“偶然采样误判”。
    • 每个 Case 建议 跑 3 次,取均值与波动范围。
  • 设备覆盖:高/中/低端机都要跑。机型选择建议以线上监控后台 Top 机型为准。
  • 对比方式:优化前后必须给出 Before/After 数据与截图证据(Profiler/Memory Profiler/Frame Debugger/Xcode 等)。

测试频率建议(工程化节奏)

  • 新功能/大活动上线前:对新增模块做专项性能测试(重点关注 CPU/GPU 峰值与内存驻留)。
  • 底层架构/核心链路改动:必须做针对性测试(代码效率、GC、资源驻留、加载尖刺)。

流程

上述只是列举了我们常用的性能优化工具,接下来我大概叙述一下我在做性能优化的大概流程,不展开详细的内容分析。

对于新的功能模块(Feature/专项优化 PR)

  1. 复现问题:给出可复现路径(机型/画质档/场景/操作步骤/出现概率)。
  2. 建立基线:抓一份“问题版本”的 Profiler/Memory/GPU 证据。
  3. 定位瓶颈归属
    • Profiler:确认是否 CPU 超预算、热点函数与调用链
    • Memory Profiler:确认是否驻留不回落/泄漏/大头资源
    • GPU:在高/中/低端机跑一遍,判断是否 GPU 超预算;辅助查看 Overdraw、Fillrate
  4. 提出方案与取舍:给出“为什么选这个方案”的理由与风险点。
  5. 实现与验证:同 Case 同口径抓 After 数据,对比收益与副作用。
  6. 回归验证:覆盖关键场景(登录/切场景/战斗/主城/长时间挂机/反复进出)。
  7. 输出 PR 报告:把证据链与结论固化,便于评审与后续追溯。

整个项目性能检测(版本体检/回归)

主要用 UPR(或等价的自动化/半自动化流程)跑整体性能,通过报告发现回归点并对症下药:

  • 定位“版本差异最大的 Case/指标”
  • 回到对应模块用 Profiler/Memory/GPU 工具补齐证据链
  • 形成“回归清单 + 责任模块 + 修复计划”

性能模块汇总

内存

音频/声音

要采集:AudioClip 总量、长音频是否流式、解码/格式、切换场景是否回收。

常见信号:

  • 切场景/账号切换后音频资源不回落
  • 大量 stereo、采样率过高、同时播放过多

常用抓手:

  • Force To Mono(适用时)、降低采样率、合理 Compression
  • 长音频 Streaming,短音效 Decompress on load(按场景权衡)
  • 音频预加载/池化,避免频繁加载卸载尖刺

网格(Mesh)

要采集:Mesh 数量、总顶点/三角形、重复网格、SkinnedMesh 占比。

常见信号:

  • 主城/大世界峰值 Mesh 飙升、重复驻留
  • 过重 SkinnedMesh 引发 CPU/GPU 双高

常用抓手:

  • LOD / Impostor(远景)、合并策略(谨慎,避免“超大 Mesh”)
  • 共享 Mesh / 减少重复实例化

纹理(Texture)

要采集:纹理总内存、Top 纹理、是否 Mipmap、压缩格式、是否重复驻留。

常见信号:

  • 峰值不回落(切换后重复纹理残留)
  • UI/特效大图导致峰值异常

常用抓手:

  • 纹理压缩、分辨率分级(低端机降档)
  • 图集/Texture2DArray(适用时)、减少重复贴图
  • 检查 Read/Write Enabled、MipMap 使用是否合理

动画(Animation)

要采集:Animator/Controller 数量、Clip 驻留、Avatar/SkinnedMesh 占用。

常见信号:

  • 大量 Animator 同屏导致内存 + CPU 开销明显

常用抓手:

  • 动画裁剪、减少状态机复杂度
  • 同屏大量单位:评估 GPUAnimation/烘焙方案(你笔记里已有)

Shader

要采集:Shader/变体数量、运行时编译尖刺、Shader 相关内存。

常见信号:

  • Shader.CreateGPUProgram 引发偶发大尖刺

常用抓手:

  • 变体裁剪(Strip)、预热(Warmup)、控制首次出现时机
  • 材质复用,减少变体/关键字组合爆炸

粒子系统

要采集:粒子实例数、贴图/材质数量、透明覆盖率(Overdraw 关联)。

常见信号:

  • 大战斗峰值内存与带宽飙升

常用抓手:

  • 贴图压缩/图集、特效分级(低端机粒子上限)
  • 控制透明层数与屏幕覆盖率

CPU

动画(CPU)

要采集:Animator.Update、SkinnedMesh、骨骼数量、同屏角色数量。

常见信号:

  • CPU Timeline 动画相关模块长期占大头

常用抓手:

  • 降低骨骼/动画更新频率、LOD 动画、可见性驱动
  • 同屏大量单位:评估烘焙/GPUAnimation

用户脚本(Scripts)

要采集:Main Thread Top Hotspots、GC Alloc、Update 链路、同步等待。

常见信号:

  • 持续超预算:脚本逻辑重
  • 偶发尖刺:GC/IO/同步加载/锁争用/日志

常用抓手:

  • Update → 事件驱动/分帧;缓存引用;减少临时分配
  • 资源加载改异步、控制加载时机;尖刺点加埋点证明收益
  • UI/字符串拼接/频繁 new 的 GC 治理(你笔记里 NGUI 优化就属于这块)

GPU

渲染(Render)

要采集:GPU Frame time、主要 Pass 成本、相机栈、后处理开销。

常见信号:

  • GPU 长期超预算或某些后处理开启后明显变差

常用抓手:

  • 开关对比:后处理、阴影、额外光源、Render Scale、MSAA
  • 相机栈精简,避免重复渲染路径

填充率(Fillrate)

要采集:全屏后效、透明物、雾/云、UI叠加的像素成本。

常见信号:

  • 分辨率一提升就崩、或低端机尤其差

常用抓手:

  • 降 Render Scale、降低后效迭代/采样
  • 降透明覆盖率、减少全屏叠加层

Overdraw

要采集:Overdraw 视图(Scene/RenderDoc/Frame Debugger 辅助),重点看特效/UI/雾。

常见信号:

  • 战斗同屏特效导致 GPU 断崖式下降

常用抓手:

  • 粒子分级、控制透明排序与生命周期、降低屏幕覆盖率

Draw Call

要采集:DrawCall/SetPass、SRP Batcher/Instancing 是否生效、材质切换原因。

常见信号:

  • SetPass 高、材质/关键字过多导致频繁切换

常用抓手:

  • 统一材质与关键字、启用 SRP Batcher、可实例化对象启用 Instancing
  • 大世界静态对象:批处理/分块策略(与你仓库B方向一致)

PR 报告输出(可直接复用的模板)

建议每个性能优化 PR 都附上以下内容(即使是小改动,也能极大提升评审效率与可信度)。

1. 背景与问题定义

  • 问题描述
  • 影响范围(机型/场景/玩法/频率):
  • 复现步骤
  • 预期目标(预算/指标目标):

2. 测试与采样口径

  • 设备:高/中/低端机(型号 + 系统版本)
  • 构建配置:Development / Release(是否 Script Debugging / 是否 Deep Profile)
  • 画质档/分辨率/Render Scale/MSAA
  • 测试 Case:场景名 + 操作路径
  • 采样时长与次数

3. Baseline(优化前)

  • 核心指标(建议表格化):
指标Before备注
FPS(稳态)
CPU Main(ms)
GPU Frame(ms)
内存峰值(MB)
内存回落(MB)
GC Alloc(KB/frame)
尖刺(ms)发生点/频率
  • 证据截图/文件:Profiler 截图、Memory Profiler Snapshot、Xcode Capture 等(脱敏)

4. Root Cause(结论必须可被证据支撑)

  • 归属:CPU / GPU / Memory / IO / 资源驻留 / 变体编译 / 脚本分配
  • 关键证据:热点函数/调用链、分配栈、渲染 Pass 组成、材质切换原因等
  • 为什么会发生:业务逻辑与引擎机制的解释(避免“只会背结论”)

5. 方案与实现

  • 方案描述
  • 关键改动点(模块/类/资源/配置):
  • 取舍与风险:兼容性、画面差异、资源包体、线上回滚策略等

6. After(优化后对比)

指标BeforeAfter变化备注
FPS(稳态)
CPU Main(ms)
GPU Frame(ms)
内存峰值(MB)
内存回落(MB)
GC Alloc(KB/frame)
尖刺(ms)
  • 证据截图/文件(同口径):

7. 回归点与发布策略

  • 回归覆盖:登录/切场景/战斗/主城/长时间运行/反复进出
  • 监控指标:线上 FPS/卡顿率/内存峰值/崩溃率等
  • 回滚条件:出现明显画面/性能回退或崩溃上升时的策略