蓝图性能与优化
自动关联目录:蓝图性能与优化
1. 定位
蓝图比 C++ 慢,但慢在哪里要有准确认识——否则要么过度恐慌(全改 C++),要么完全不在意(最后救不回来)。
一句话定位:蓝图的开销主要是"每节点调用开销 + 无法内联",不是"语言本身很慢"。所以"节点数 × 调用频率"才是成本公式。
2. 开销来源
| 来源 | 说明 |
|---|---|
| 虚拟机解释/调用开销 | 每个节点一次 |
| 无法内联 | 小函数在 C++ 里会被内联,蓝图不会 |
| 反射调用 | 蓝图调 C++ 走反射(见 蓝图与 C++ 互调) |
| Tick | 蓝图 Tick 每帧跑整张图 |
| Cast / 查找 | GetAllActorsOfClass 这类很贵 |
| 大量字符串/容器操作 | 与 C++ 同理但更慢 |
成本 ≈ 节点数 × 调用频率。因此:
- 每帧跑的图 → 节点数要少,或下沉 C++
- 事件驱动的图 → 节点多一点无所谓
3. 优化手段
| 手段 | 说明 |
|---|---|
| 减少 Tick | 改用事件/定时器/委托(见 Actor 生命周期) |
| 缓存引用 | 不要每帧 Cast 或 GetAllActorsOfClass |
| 热路径下沉 C++ | 每帧跑的、成规模的 |
| 拆分大图 | 但拆太碎也会增加调用开销 |
| 用 Timer 代替每帧检查 | 降低频率 |
| 数据结构用 C++ | 大量容器运算 |
| 避免蓝图里的深递归 | — |
最常见的一条:蓝图里每帧 GetAllActorsOfClass 或 Cast —— 应改为启动时缓存引用。
4. 常见误解
| 误解 | 事实 |
|---|---|
| "蓝图一定很慢" | 事件驱动的低频蓝图开销可忽略 |
| "全改 C++ 就好" | 迭代成本上升,且不一定解决真正的瓶颈 |
| "节点越少越好" | 拆太碎也会增加调用开销,要平衡 |
| "蓝图编译后就和 C++ 一样快" | 不会被内联,仍有调用开销 |
5. 代价与权衡
| 设计 | 收益 | 代价 | 什么时候不该用 |
|---|---|---|---|
| 蓝图 Tick | 简单直观 | 每帧成本 | 能事件驱动就不要 Tick |
| 每帧 Cast | — | 明显浪费 | 必须缓存 |
| 热路径下沉 C++ | 性能 | 迭代变慢 | 稳定的热路径才值得 |
| 拆分成小函数 | 可复用 | 调用开销增加 | 热路径不要过度拆 |
| 缓存引用 | 大幅省 | 要管理生命周期(用弱引用) | — |
6. 踩坑与排查
| 坑 | 现象 | 怎么验证 |
|---|---|---|
| 蓝图 Tick 做重活 | Game 线程高 | stat game;改用事件驱动 |
| 每帧 Cast / 查找 | 慢 | 缓存引用 |
| 蓝图里大容器运算 | 慢 | 下沉 C++ |
| 大量蓝图同时 Tick | 帧率掉 | 减少 Tick;按 Significance 降频 |
| 以为改 C++ 就能解决 | 瓶颈不在蓝图 | 先 stat unit 定位 |
| 缓存了裸指针 | 对象销毁后崩溃 | 用弱引用(见 GC) |
7. 排查顺序
1. stat unit → Game 高才可能是蓝图问题
2. 找每帧跑的蓝图(Tick / 定时器)
3. 检查其中的 Cast 与查找 → 缓存
4. 节点规模大 → 下沉 C++
5. 大量实例 → 降频或 Significance参考
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/4a23c502.html
更新于:2026年10月10日