硬引用:加载链上的多米诺

现象:打开编辑器,进游戏前卡 30 秒; 生成一个新角色,内存涨 200MB;打包后启动慢一倍。

根因:硬引用(Hard Reference)。当蓝图 A 里直接引用了资产 B(材质、模型、蒙太奇……),加载 A 时引擎必须连带加载 B;B 若又引用 C、C 又引用 D……整条链全会被拖进内存。

BP_PlayerCharacter(角色蓝图)
 ├─ 引用 M_Player_Master(主材质,60MB) ──┬─ 引用 T_Body_Diffuse(40MB)
 ├─ 引用 A_Attack_Montage(蒙太奇,30MB)   ├─ 引用 T_Body_Normal(40MB)
 └─ 引用 WBP_HUD(UI,含全部图标)          └─ 引用 M_Player_Master
 → 进游戏时全部加载,哪怕玩家根本还没换装

三种解法

① 软引用(Soft Reference):把引用改成"按需加载"

  • C++:TSoftObjectPtr<UAnimMontage> / TSoftClassPtr<AActor>
  • 蓝图:把变量类型从 Object Reference 改成 Soft Object Reference
// 硬引用:加载类即加载蒙太奇
UPROPERTY(EditDefaultsOnly, Category="Combat")
UAnimMontage* AttackMontage;

// 软引用:只在真正播放时加载
UPROPERTY(EditDefaultsOnly, Category="Combat")
TSoftObjectPtr<UAnimMontage> AttackMontage;

// 用时:
if (UAnimMontage* M = AttackMontage.LoadSynchronous())
    PlayMontage(M);

② 分层加载:大厅角色、战斗角色分开,进战斗才加载战斗资源(用 Load 节点 + Level Streaming 或资产管理器)。

③ 依赖链诊断:别凭猜。用引用查看器(Reference Viewer):资产右键 → Reference Viewer → Show Referenced Assets。看到那条依赖链,你就知道卡在谁身上。

与之相关:"蓝图里保存的引用"是隐藏重灾区

新人常在蓝图变量里直接存一个 StaticMeshComponent 引用或贴图引用,以为只是个指针——硬引用就是硬引用,不管是变量还是属性。凡是"可能很大"的资源,一律软引用化。

一个量化感受

做过一次对比:一个角色蓝图直接引用了 12 个蒙太奇和 8 个材质实例。改成软引用后:

指标 修改前 修改后
进游戏加载耗时 8.4s 3.1s
角色常驻内存 ~410MB ~120MB
首次播放攻击动画 0ms(已加载) +0.4s(首次加载)

换来的代价是"首次使用时的小卡顿"——用预加载(进关卡时提前 Load)可以消除。

本章小结

  • 硬引用形成"加载链",一个蓝图能把整条资源树拖进内存。
  • 解法:软引用(TSoftObjectPtr/Soft Object Reference)+ 分层加载 + Reference Viewer 诊断。
  • 大资源一律软引用化,首次使用的卡顿用预加载消除。