Unity3D 优化深入浅出 5-内存篇(公众号笔记)
ABSTRACT
2018-01 公众号笔记(原稿标注「待编辑」),优化系列第五篇。区分 Mono 托管内存与 Unity 原生资源内存两条线,给出托管侧减 GC 七法与资源侧 AssetBundle 加载/卸载机制、纹理/网格/音频压缩要点,并讲解 Profiler 内存面板(Used/Reserved、GfxDriver 等指标)的读法。
核心要点
- Unity 内存两大类:Mono 托管堆内存(C# 脚本对象,有 GC)与 Unity 原生内存(纹理、网格、GameObject、引擎子系统)。
- 托管堆上每个封装对象背后还对应一份引擎内部对象的原生内存分配,删脚本对象不等于释放全部内存。
- Mono 侧优化:对象池减少实例化/销毁;StringBuilder 代替字符串拼接;Start/Init 中缓存查找结果;减少函数调用栈(如三元运算代替 Mathf.Abs);定时任务用 InvokeRepeating;GetComponent 结果缓存复用;内置数组优于 ArrayList(内存紧凑、缓存友好)。
- AssetBundle 加载三阶段:加载 AB 文件得到内存镜像 → AssetBundle.Load 反序列化出 Asset 对象 → Instantiate 实例化(GameObject 是复制,Shader/贴图是引用,网格/材质是引用+复制)。
- 卸载规则:Unload(false) 只释放 AB 内存镜像;Unload(true) 连 Load 出的 Asset 一并销毁——实例未销毁就 Unload(true) 会出现经典的紫色(丢失材质)物体。
- 纹理压缩:iOS 用 PVRTC、Android 用 ETC,省内存且读取快但降画质;2D 纹理不必开 mipmap(约增 33% 内存),3D 纹理一般开。
- 网格:可合并与压缩(压缩坑多不建议);音频尽量压缩;粒子用完及时销毁;控制 GameObject 总数。
- Profiler 简易模式:Used Total 是实际使用物理内存,Reserved Total 是 Unity 向系统预申请的缓存池;Used 降后 Reserved 不一定同步回落。
- 内存分类读数:Unity(底层)、Mono(托管堆,只与脚本有关)、GfxDriver(显存,纹理+顶点/索引缓冲)、FMOD(音频);详细模式 Take Sample 可看每个资源的占用。
关键实体与概念
Mono 托管堆、GC、AssetBundle、Unload(true/false)、对象池、PVRTC/ETC 纹理压缩、mipmap、Profiler、GfxDriver、Reserved 内存
关联概念
来源回溯
- 原始文件:
raw/ip/wechat_articles/Unity3D优化深入浅出5-内存篇(待编辑).md(2018-01-11)
时效性评估
- 仍有效:托管/原生双内存模型、AB 加载三阶段与 Unload 语义、纹理压缩与 mipmap 的权衡、Profiler 读数方法至今通用。
- 已过时:Mono 运行时正被 IL2CPP 全面取代(iOS 早已强制);ETC/PVRTC 之上已有 ASTC 成为主流压缩格式;AssetBundle 手动管理已被 Addressables 封装,卸载规则仍同但 API 层变化大;现代 Profiler 增加了 Memory Profiler 包,分析粒度远超文中简易/详细两模式。