内存剖析

自动关联目录:内存剖析

1. 定位

内存问题的难点是"不知道谁在占用":引擎自己有池、有缓存、有流式,外面看到的进程内存和引擎内部账对不上。

一句话定位:先用 memreport 分类别,再针对最大那一类深入——不要在总量上纠结。

2. 快速命令

命令作用
memreport -full生成完整内存报告(第一命令)
stat memory / stat streaming总览与流式状态
obj list class=XXX统计某类对象数量(查泄漏)
obj refs name=XXX看谁在引用某对象
DumpLoadedAssets列出已加载资产("为什么内存下不来")
stat rhi渲染资源数量
LLM(Low Level Memory)逐系统追踪,需启动时 -llm

3. 分类与排查方向

类别排查方向
纹理分辨率、压缩格式、mip、流式(见 移动端渲染)
网格 / NaniteLOD 套数、Nanite 数据
动画见 动画压缩与内存
音频是否流式、采样率
光照贴图见 光照与烘焙
NavMesh多 Agent 会有多份(见 导航系统)
着色器 / PSO变体数量、PSO 保留(见 PSO 预缓存)
UObject泄漏与引用(见 GC)
渲染目标分辨率与数量

平台工具(详见 UE性能优化工具 的内存章节):Android Studio、LoliProfiler、Custom Built Profiler、Memreport、RHI Memory、XCode Allocations 等。

4. 查泄漏

1. 反复进出关卡,内存是否只增不减?
2. obj list class=你的类 → 数量是否只增不减
3. obj refs name=XXX → 谁在持有它
4. DumpLoadedAssets → 哪些资产没卸载
常见泄漏源说明
静态变量持有 UObject静态区不在 GC 引用图里(见 GC)
未移除的委托委托持有对象
未清理的容器非 UPROPERTY 容器不构成引用,但会阻止释放
常驻 ActorWP 里被关卡蓝图引用(见 World Partition)
未释放的渲染资源见 RDG

5. 代价与权衡

手段收益代价注意
memreport -full一次性全景生成慢对比两次报告看增长
LLM逐系统、精确需启动参数,有开销深度排查用
平台内存工具看到真实分配与引擎内部账对不上结合两者看
降低纹理分辨率收益大画质下降按平台分级
减少常驻资产收益大需要加载管理见 资源加载

6. 踩坑与排查

坑现象怎么验证
直接看进程内存与引擎账对不上用 memreport + 平台工具对照
只看总量不知道改哪必须分类别
忽略流式以为泄漏看 stat streaming
反复进出关卡内存增长查常驻引用(关卡蓝图、静态变量、委托)
多份 NavMesh / 多套 LOD内存翻倍检查 Agent 与 LOD 配置
PSO 保留过多内存涨见 PSO 篇的 KeepInMemory 系列
编辑器内存 ≠ 打包结论不适用测打包版本
移动端 OOM目标机型限制按最低配机型定预算

7. 排查顺序

1. memreport -full → 分类别,找最大项
2. 最大项进对应分支(纹理/动画/光照/导航/着色器)
3. 内存只增不减?→ obj list / obj refs / DumpLoadedAssets 查泄漏
4. 需要逐系统 → LLM
5. 移动端 → 按最低配机型定预算,测打包

参考