UE 性能分析工具与方案 一、代码插桩宏(Code Instrumentation Macros) 通过在 C++ 代码中插入统计宏,标记需要测量耗时的代码块。这些数据会被 Unreal Insights 和 stat 命令采集。
1. 循环计数器宏(Cycle Counter)
宏
用途
说明
DECLARE_STATS_GROUP(GroupDesc, GroupName, StatType)
声明统计分组
在 .cpp 顶部声明,将相关统计归类
DECLARE_CYCLE_STAT(StatName, StatId, GroupName)
声明一个循环计数统计
通常在文件作用域声明
SCOPE_CYCLE_COUNTER(StatId)
测量当前作用域耗时
作用域结束时自动记录
QUICK_SCOPE_CYCLE_COUNTER(StatId)
快速声明+测量
无需额外 DECLARE,一行搞定
SCOPED_NAMED_TIMER(Text, Flags)
快速命名计时器
无需提前声明,直接使用字符串标识
典型用法:
1 2 3 4 5 6 7 8 9 10 11 12 DECLARE_STATS_GROUP (TEXT ("MyGame" ), STATGROUP_MyGame, STATCAT_Advanced);DECLARE_CYCLE_STAT (TEXT ("ProcessAI" ), STAT_ProcessAI, STATGROUP_MyGame);void AMyActor::Tick (float DeltaTime) { Super::Tick (DeltaTime); SCOPE_CYCLE_COUNTER (STAT_ProcessAI); }
2. 快速计时(无需预声明) 1 2 3 4 5 6 7 8 9 10 11 12 13 void MyFunction () { QUICK_SCOPE_CYCLE_COUNTER (STAT_MyFunction_LoadData); } void MyFunction () { SCOPED_NAMED_TIMER ("MyFunction_LoadData" , FStatGroup::Get_STATGROUP_Threads ()); }
3. 计数统计宏(Counter Stats)
宏
用途
DECLARE_DWORD_ACCUMULATOR_STAT(StatName, StatId, GroupName)
声明累计计数器
INC_DWORD_STAT(StatId)
计数器 +1
DEC_DWORD_STAT(StatId)
计数器 -1
SET_DWORD_STAT(StatId, Value)
设置计数器值
1 2 3 4 5 6 DECLARE_DWORD_ACCUMULATOR_STAT (TEXT ("ActiveEnemies" ), STAT_ActiveEnemies, STATGROUP_MyGame);INC_DWORD_STAT (STAT_ActiveEnemies);DEC_DWORD_STAT (STAT_ActiveEnemies);
4. 内存统计宏
宏
用途
DECLARE_MEMORY_STAT(StatName, StatId, GroupName)
声明内存统计
TRACK_OBJECT_STAT(ObjectClass, StatId)
追踪 UObject 内存占用
二、Unreal Insights UE5 官方推出的高性能分析工具,取代旧版 Session Frontend / Profiler。
启动方式
编辑器菜单:Tools → Unreal Insights
命令行启动:UnrealInsights.exe
运行游戏时添加参数:-trace=cpu,gpu,memory,loadtime
核心功能模块
模块
功能
查看内容
Timing Insights
CPU/GPU 时间线
帧时间、函数调用耗时、线程活动、任务图(TaskGraph)
Memory Insights
内存分配追踪
内存泄漏、分配热点、对象生命周期
Networking Insights
网络分析
网络包大小、RPC 调用、复制带宽
Loading Insights
加载分析
资源加载耗时、异步加载瓶颈
Trace 通道(Channels) 启动时可指定采集哪些通道的数据:
1 -trace=cpu,gpu,memory,loadtime,net,frametime
通道
内容
cpu
CPU 计时、线程调度
gpu
GPU 渲染耗时、Draw Call
memory
内存分配/释放事件
loadtime
资源加载时间
net
网络复制数据
frametime
帧时间统计
常用分析场景
帧时间分析 :Timing Insights → 展开 Game Thread → 找到耗时最长的 SCOPE_CYCLE_COUNTER 标记
GPU 瓶颈定位 :Timing Insights → GPU 视图 → 查看各 Pass 耗时
内存泄漏排查 :Memory Insights → 对比两个时间点的内存快照
加载卡顿 :Loading Insights → 排序找出加载最慢的资源
三、Stat 命令 在编辑器或运行时通过控制台(~ 键)输入 stat 命令查看实时性能数据。
常用命令
命令
说明
stat fps
显示帧率和帧时间
stat unit
显示各线程耗时(Game/Draw/RHI/GPU)
stat unitgraph
以图表形式显示线程耗时
stat scenerendering
场景渲染统计(Draw Call、三角形数、可见物体数)
stat engine
引擎基础统计
stat streaming
资源流式加载统计
stat memory
内存使用概览
stat particles
粒子系统统计
stat physics
物理模拟统计
stat net
网络统计
stat dumphitches
记录卡顿信息到日志
关键指标解读 1 2 3 4 5 6 7 8 9 10 11 stat unit 输出示例: Frame: 33.2 ms ← 整帧耗时(目标 16.67ms = 60fps) Game: 12.1 ms ← Game Thread(逻辑/AI/动画) Draw: 5.3 ms ← Render Thread(渲染命令准备) RHI: 4.1 ms ← RHI Thread(GPU 指令提交) GPU: 18.7 ms ← GPU 实际渲染耗时 瓶颈判断: - Game 高 → 逻辑代码优化(减少 Tick、优化 AI) - Draw 高 → 减少可见物体、LOD、裁剪优化 - GPU 高 → 材质/光照/后处理优化
自定义 Stat 分组 1 2 DECLARE_STATS_GROUP (TEXT ("My Game Stats" ), STATGROUP_MyGame, STATCAT_Advanced);
Stat 命令进阶
命令
说明
stat startfile
开始记录统计到文件
stat stopfile
停止记录,生成 .ue4stats 文件,可用 Unreal Insights 打开
stat dumphitches
开启卡顿记录,超过阈值时输出调用栈到日志
t.MaxFPS 60
限制最大帧率
r.VSync 0
关闭垂直同步,测试裸性能
四、GPU 分析工具 1. ProfileGPU(控制台命令) 输入 ProfileGPU 后,会在 Output Log 中输出当前帧的 GPU Pass 明细:
1 2 3 4 5 6 Scene (18.2ms) ├── Base Pass (6.1ms) ├── Shadow Pass (3.2ms) ├── Lighting (4.8ms) ├── Translucency (2.1ms) └── Post Process (2.0ms)
2. GPU Visualizer(vis 命令)
命令
说明
vis
打开 GPU Visualizer 窗口
ProfileGPU
单帧 GPU Profile
r.ScreenPercentage 50
降低渲染分辨率测试 GPU 负载
3. RenderDoc / PIX
RenderDoc :通用 GPU 帧分析器,支持 UE5。可逐 Draw Call 检查像素历史、Shader 资源。
PIX (Windows) :微软 GPU 分析工具,对 Xbox/DirectX 项目友好。
Xcode GPU Profiler (macOS/iOS) :Metal 平台 GPU 分析。
这个功能(原本是UE4的)被整合进了 UE5 Unreal Insights 的 GPU 视图中。
五、内存分析
工具/命令
说明
obj list
列出所有 UObject 及其内存占用
obj list class=StaticMesh
列出指定类型的对象
memreport -full
生成完整内存报告
stat memory
实时内存统计
mimalloc
UE5 可选的现代内存分配器(.ini 中配置)
六、蓝图性能分析
Blueprint Profiler :编辑器菜单 Tools → Blueprint Profiler
查看蓝图节点执行耗时,定位慢节点
优化建议:热点蓝图逻辑迁移到 C++
七、调试技巧 1. UE_LOG 标记用时 用日志打印时间戳来测量代码段耗时,适合快速排查:
1 2 3 4 UE_LOG (LogTemp, Warning, TEXT ("disconnect(): waiting for receiveThread %s" ), *FDateTime::Now ().ToString ());QUICK_SCOPE_CYCLE_COUNTER (STAT_WaitReceive);WaitForSingleObject (receiveThread, INFINITE);UE_LOG (LogTemp, Warning, TEXT ("disconnect(): receiveThread finished %s" ), *FDateTime::Now ().ToString ());
输出示例:
1 2 Warning LogTemp disconnect(): waiting for receiveThread 2025.12.04-16.48.31 Warning LogTemp disconnect(): receiveThread finished 2025.12.04-16.48.46
两个时间戳相减即可得到该段代码的实际耗时(此处约 15 秒)。
2. 关闭局部代码优化 调试时编译器优化会干扰断点和变量观察,可对指定代码段临时关闭优化:
1 2 3 4 #pragma optimize("" , off) #pragma optimize("" , on)
"" 表示使用当前工程设置的优化选项集合
off/on 用来临时关/开优化
只对它之后的代码生效(直到再 on 回去),一般包住某个函数实现
3. 自动化性能测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 IMPLEMENT_SIMPLE_AUTOMATION_TEST ( FMyPerfTest, "Performance.MyGame.StressTest" , EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::ProductFilter ) bool FMyPerfTest::RunTest (const FString& Parameters) { AddCommand (new FWaitLatentCommand (5.0f )); AddCommand (new FMeasureTimeLatentCommand ( TEXT ("StressTest_100Enemies" ), [this ]() { Spawn100Enemies (); }, 0.5f )); return true ; }
八、性能分析流程建议 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 1. 定位瓶颈 stat fps + stat unit → 确认是 CPU 还是 GPU 瓶颈 2. CPU 瓶颈 ├─ stat unitgraph → 确认哪个线程慢 ├─ Unreal Insights Timing → 找到具体函数 ├─ 检查 Tick、蓝图、GC、物理 └─ 用 SCOPE_CYCLE_COUNTER 细化测量 3. GPU 瓶颈 ├─ ProfileGPU → 看 Pass 分布 ├─ stat scenerendering → Draw Call / 三角形数 ├─ GPU Visualizer → 可视化分析 └─ RenderDoc → 深入单个 Draw Call 4. 内存问题 ├─ stat memory → 概览 ├─ memreport -full → 详细报告 └─ Unreal Insights Memory Insights → 内存泄漏追踪 5. 快速调试 ├─ UE_LOG + 时间戳 → 快速定位耗时 └─ #pragma optimize("", off) → 关闭优化方便断点调试
参考文章 https://zhuanlan.zhihu.com/p/273608458