结论

  • Unity 移动端内存主要分三块:资源内存、引擎模块内存、托管堆内存;优化时不要只盯 GC Alloc 或 Mono。
  • 大多数项目的内存压力来自资源,尤其是 Texture、Mesh、AnimationClip、AudioClip、Material、Shader、Font、Text Asset。
  • 判断内存泄漏不能只看“一次进出场景后没有完全回落”,需要做同场景多轮对比、跨场景资源对比和平台内存趋势验证。
  • AssetBundle 的问题通常不是“加载失败”,而是 WebStream / SerializedFile / Bundle 对象 / 已加载资源 / 实例化对象的生命周期没有拆清楚。
  • 性能优化要形成闭环:确定设备与路径、采集基线、定位类型、修改方案、复测数据、沉淀规则。

资料收敛说明

  • 本页已将原先 11 条参考链接压缩为 2 条核心引用,重复导航页、同类 API 细节页和低信噪比补充资料不再逐条公开保留。
  • 正文已优先沉淀选型标准、排查流程、风险边界和常用工具定位,后续新增资料应继续转成正文结论,而不是直接堆叠链接。
  • 文末只保留官方文档、代表性开源项目和少量仍值得回看的补充阅读。

适用场景

  • Android / iOS 包体或运行时内存过高。
  • 场景切换后内存没有下降,或者多次切换后持续增长。
  • 游戏长时间运行后出现卡顿、闪退、OOM 或系统杀进程。
  • Profiler 中出现频繁 GC、加载尖峰、UI 重建或渲染压力。
  • 需要做版本发布前的性能巡检和资源审计。

指标口径

  • Reserved Total:Unity 已向系统申请的总内存,通常大于 Used Total,不一定会立刻还给系统。
  • Used Total:Unity 当前实际使用的内存,更适合判断引擎内存和资源内存是否持续增长。
  • Reserved GFX:重点关注纹理和网格资源,通常要从压缩格式、顶点数据、资源冗余和资源泄漏排查。
  • ManagedHeap.UsedSize:逻辑代码申请的托管堆内存,过大通常意味着配置表、容器、字符串、临时对象或缓存策略需要优化。
  • PSS / Instruments:平台侧口径包含系统缓存、驱动、第三方库等,不应和 Unity Profiler 做一一对应,只适合看趋势。

排查流程

  1. 固定测试条件:设备、系统版本、Unity 版本、资源包版本、画质档位、网络状态、操作路径。
  2. 采集基线:首包启动、主界面、核心战斗、切场景、长时间挂机、反复打开高频 UI。
  3. 粗分问题类型:先判断是资源、AssetBundle、托管堆、渲染、UI、第三方插件还是平台侧内存。
  4. 做快照对比:同一场景不同时刻对比,或主城/战斗等不同场景对比,找“不该共同存在”的资源。
  5. 对 GPU 渲染瓶颈和移动端抓帧问题,可引入 SnapDragonProfilerCLI 这类无头工具链,把高通设备帧捕获、离线分析、HTTP 服务和 WebUI 浏览串成可重复流程,避免只靠本地手工点界面抓数据。
  6. 查生命周期:确认资源是预加载、常驻缓存、对象池保留,还是被静态变量、容器、事件、单例错误持有。
  7. 修复后复测:必须用同一路径重新采样,比较峰值、回落值、增长趋势、GC 频率和帧耗时。

高频问题

资源内存

  • 纹理通常是移动端最大内存来源,一张 2048x2048 非压缩纹理可能直接消耗十几 MB。
  • 纹理分辨率影响内存和加载时间,1024x1024 相对 512x512 通常是 4 倍像素量,不能只凭肉眼提升决定尺寸。
  • 非压缩格式如 RGBA32、ARGB32、RGB24 显示效果好,但内存占用大;应优先用硬件支持的压缩格式。
  • Android 低端兼容常见 ETC1,但 ETC1 不支持 Alpha;可以拆 RGB 与 Alpha,或在中高端设备使用 ETC2 / ASTC。
  • UI Sprite 一般不需要 Mipmap;开启后内存大约增加 1/3,且对 UI 渲染收益有限。
  • Read/Write Enabled 只在确实需要 CPU 读写纹理时开启,否则可能让纹理内存翻倍。
  • Mesh 需要检查无用的 Normal、Color、Tangent;这些顶点属性会增加文件体积和内存,并可能在合批时放大影响。

AssetBundle / 资源生命周期

  • 通过 new WWW 或 CreateFromMemory 加载 Bundle 时,容易产生较大的 WebStream;通过缓存或文件方式加载通常产生较小的 SerializedFile。
  • CreateFromFile / LoadFromCacheOrDownload 更省常驻 WebStream,但可能引入磁盘 IO、文件句柄和 PersistentManager.Remapper 增长问题。
  • AssetBundle.Unload(false) 只卸载 Bundle 对象,已加载资源仍留在内存;如果之后重新加载同一资源,可能出现冗余资源。
  • AssetBundle.Unload(true) 会连同已加载资源一起卸载,但容易导致仍被场景对象引用的资源丢失,不适合作为常规粗暴清理手段。
  • Resources.UnloadUnusedAssets() 可以清理未引用资源,但 CPU 开销大,不建议在战斗或高频交互中直接调用。
  • 被静态变量、缓存容器、单例、对象池、事件订阅引用的资源,不会因为 UnloadUnusedAssets() 自动释放。

泄漏与冗余

  • 进出场景后内存没有完全回落不一定是泄漏,可能是资源常驻、Mono 堆只升不降、系统缓存、驱动缓存或平台统计口径差异。
  • 更可靠的判断方式是多次在同一场景之间来回切换:如果 Unity 内存或平台 PSS 持续单调增长,才需要重点怀疑泄漏。
  • 资源泄漏常见原因是资源被放进容器、缓存、静态字段或对象池,但场景切换时没有 Remove、Clear 或释放引用。
  • 冗余资源常见于同一资源被打入多个 Bundle,或运行时修改 Renderer.material 导致 Material 实例化。
  • 对 Material 变体需求固定的情况,优先制作有限数量的 Material 并切换引用,避免运行时批量产生 (Instance) 材质。
  • 资源冗余可以按“同一资源数量峰值 > 1”“不该跨场景共同出现”“Bundle 依赖重复打包”三个方向排查。

GC 与托管分配

  • 不要在 Update、战斗循环、滚动列表刷新、输入处理等高频路径中持续 new Class / Container / Array。
  • 即使每帧只分配很少对象,长时间运行也会推高 GC 频率和 Mono 堆峰值。
  • 大配置表一次性加载会快速推高 Mono 堆;如果首进游戏 Mono 很高,优先检查配置表是否可拆分、压缩或按需加载。
  • 日志输出本身可能造成 CPU 和堆内存开销,线上包应严格控制日志级别、拼接字符串和调用路径。
  • 字符串拼接、装箱、闭包、LINQ、临时 List/Dictionary、协程对象、频繁委托创建都需要结合 Profiler 调用栈确认。
  • 优先用对象池、容器复用、StringBuilder、预分配容量、减少临时 lambda 和按需加载降低分配。

动画、粒子与材质

  • Animator 对骨骼动画应尽量开启 Optimize Game Objects,减少不必要的 Transform 层级更新;UI Animator 不适用该优化项。
  • 动画片段中的 Scale 曲线、过高浮点精度会增加内存,若表现无明显收益,应压缩精度或移除无效曲线。
  • 材质切换 Shader 后可能残留无用纹理采样,需要清理不再使用的贴图引用,避免被带进包或运行时占用内存。
  • 粒子系统要限制粒子数上限和粒子贴图尺寸;多数普通特效不应默认使用大图和过高粒子上限。
  • 纯色纹理可以用 Shader 参数替代,不需要专门占用一张纹理资源。

优化决策

  • 优先级一:资源审计。先查大图、非压缩图、UI Mipmap、Read/Write、Mesh 冗余属性、重复资源、未引用资源。
  • 优先级二:场景回落。反复切主城/战斗/副本,确认资源是否按预期释放,重点看共同资源和生命周期异常资源。
  • 优先级三:加载路径。拆清 AssetBundle 加载方式、卸载方式、依赖关系、缓存策略和大资源初始化时机。
  • 优先级四:托管分配。重点清理高频函数分配、大配置表、日志、字符串、临时容器和 UI 刷新路径。
  • 优先级五:表现权衡。对纹理尺寸、动画精度、粒子数、网格面数做平台分档,而不是全平台使用同一套高规格资源。

发布前检查清单

  • 关键场景是否有性能基线数据。
  • 同一路径复测是否至少覆盖 3-5 轮场景切换。
  • 纹理是否按平台使用合适压缩格式和合理分辨率。
  • UI Sprite 是否误开 Mipmap。
  • Read/Write Enabled 是否只在确实需要 CPU 读写时开启。
  • Mesh 是否存在无用 Normal、Color、Tangent 或过高面片数。
  • 大图、重复图、纯色图、无用纹理采样、未引用资源是否已清理。
  • Bundle 是否有明确依赖关系、引用计数、卸载策略和缓存策略。
  • Unload(false) 后是否可能重新加载同一资源造成冗余。
  • UnloadUnusedAssets() 是否只在可接受卡顿的时机调用。
  • 战斗和主界面是否存在持续 GC Alloc。
  • UI 高频刷新区域是否已拆 Canvas 或做列表复用。
  • 线上崩溃、OOM、ANR 是否能关联到具体版本和资源包。

笔记沉淀方式

  • 官方文档和课程链接只放在“参考链接”,正文记录自己验证过的规则、流程和项目经验。
  • 同一类问题优先合并到本笔记,例如纹理、AssetBundle、GC、移动端内存。
  • 如果某个子主题超过一屏,可以拆成独立笔记,例如 Unity 纹理压缩策略、Unity AssetBundle 卸载机制。
  • 本笔记已用 scripts/fetch_link_content.py 抓取参考链接正文并缓存到 private/link_cache/,缓存不会发布到站点。

渲染优化

Profiler 与性能分析

GC 与内存管理

加载与资源优化

其他参考

参考链接

以下链接仅保留正文仍需回看的核心资料入口。

补充阅读