内存剖析
自动关联目录:内存剖析
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、流式(见 移动端渲染) |
| 网格 / Nanite | LOD 套数、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 容器不构成引用,但会阻止释放 |
| 常驻 Actor | WP 里被关卡蓝图引用(见 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. 移动端 → 按最低配机型定预算,测打包参考
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/583c14e2.html
更新于:2026年10月10日