加载与卡顿

自动关联目录:加载与卡顿

1. 定位

卡顿(hitch)和"平均帧率低"是两类问题:平均帧率低是持续成本,卡顿是某一帧突然做了很多事。

一句话定位:卡顿的排查核心是"那一帧多做了什么",而不是"整体哪里慢"。

2. 卡顿的常见来源

来源说明对应篇
同步加载主线程 LoadObject / LoadSynchronous资源加载与异步加载
FlushAsyncLoading把异步变同步资源加载篇
PSO 首次编译驱动现场编译PSO 预缓存
着色器编译首帧/首现材质材质与着色器编译
GC全量可达性分析GC 与对象生命周期
渲染线程同步FlushRenderingCommands管线与渲染线程
World Partition 单元加载传送/快移World Partition
阴影缓存作废尖峰VSM 重画大片页虚拟阴影贴图
动画首播解压首次播放某段动画动画压缩与内存
资源流式纹理/网格流送资源加载

3. 定位工具

工具用途
stat unitgraph看抖动最直观——尖峰一目了然
Unreal Insights看那一帧的阻塞栈与任务
stat streaming流式加载状态
stat gcGC 尖峰(见 GC 篇)
stat tsrTSR 的收敛(见 TSR)
stat PSOPrecachePSO 预缓存 miss(见 PSO 篇)
Insights 的 PSOPrecache: Missed / Too Late直接看 PSO 造成的卡顿

stat unitgraph 是发现卡顿的第一工具——数字看不出抖动,图形一眼看到。

4. 加载屏的正确做法

要点说明
必须等 PSO 预缓存完成FShaderPipelineCache::NumPrecompilesRemaining() 归零才放行(见 PSO 篇)
地形等不支持延迟策略的对象要等官方明确:landscape 不适合换默认材质或不渲染
用流式源预加载传送前先在目标位置放流式源(见 WP 篇)
Is Streaming Completed判断单元是否加载完成
首启体验要清驱动缓存测-clearPSODriverCache(见 PSO 篇)

最常见的"进游戏后 pop 与卡顿":加载屏没有等 PSO 预缓存就放行了。

5. 代价与权衡

手段收益代价什么时候不该用
异步加载不阻塞需要持有 handle 与 UPROPERTY 保活(见资源加载篇)必须立刻用到的才同步
加载屏等待消除进场卡顿加载时间变长时间过长要优化加载量而不是取消等待
预加载(流式源)传送不卡提前占用带宽与内存远处不值得预加载
PSO 预缓存消除驱动编译卡顿内存与启动时间(见 PSO 篇)几乎都应该开
FlushAsyncLoading保证就绪强制同步,制造卡顿运行时热路径不该用

6. 踩坑与排查

坑现象怎么验证
加载屏没等 PSO进游戏后 pop + 卡顿NumPrecompilesRemaining() 是否纳入逻辑
运行时 LoadSynchronous主线程卡改为异步
调 FlushAsyncLoading每帧掉帧搜索代码里所有 Flush
传送不预加载到点一片空白流式源 + Is Streaming Completed
测试没清驱动缓存卡顿测不出-clearPSODriverCache
GC 周期性尖峰每隔一段时间卡stat gc(见 GC 篇)
只测一次偶发卡顿抓不到stat unitgraph + Insights 长时间记录
只测编辑器打包后不同测打包版本

7. 排查顺序

1. stat unitgraph 确认是"尖峰"还是"整体慢"
2. 尖峰在什么时候?(进场 / 传送 / 首次出现某物体 / 周期性)
   ├─ 进场 → PSO 预缓存 + 加载屏等待
   ├─ 传送 → WP 流式源预加载
   ├─ 首次出现 → 着色器编译 / PSO / 动画解压
   └─ 周期性 → GC / 阴影重缓存
3. Insights 看那一帧的阻塞栈
4. 对应篇深入
5. 复测必须清 PSO 驱动缓存

参考