111.内存优化-资源优化-AB包和Resources
111.1 知识点
AB包与Resources资源管理的核心理念
- AB 包(或 Addressables)的使用: 实现资源热更新、减少包体大小、按需加载
- Resources 的使用: 谨慎使用、避免滥用、了解局限性
- 核心点: 项目中尽量使用 AB 包或者 Addressables 管理加载项目资源
Resources 系统解析
Resources 系统看似简单实则陷阱重重。
Resources.Load 的成本
- 同步加载: 主线程阻塞,卡顿根源
- 内存占用: 加载后常驻内存,直到明确卸载
- 初始化耗时: 首次访问 Resources 文件夹的扫描开销
适合快速原型开发和小型项目使用,但不适合中大型项目的主资源管理方案。建议仅用于关键启动资源或编辑器工具,绝对避免在运行时频繁调用。
Resources.UnloadUnusedAssets
- 作用: 卸载所有未被引用的资源
- 代价: 完整 GC 触发,主线程卡顿
- 原理: 遍历所有资源,检查引用计数为零的资源
- 建议: 在场景切换等自然断点处调用;避免在性能敏感时段调用;配合
GC.Collect()使用效果更好
Resources 内存管理陷阱
| 陷阱 | 说明 |
|---|---|
| 资源泄漏 | Resources.Load 后没有对应 Unload |
| 依赖关系 | 复杂资源依赖导致无法卸载 |
| 重复加载 | 同一资源被多次加载,产生多份实例 |
建议建立严格的加载/卸载配对机制,使用引用计数管理资源生命周期,并监控 Resources 文件夹总体大小。
Resources 使用决策流程
- 必须使用的资源 → 启动时预加载 + 引用计数管理
- 尽量不用 Resources 系统
- 频繁使用的资源 → 使用 AB 包或 Addressables 替代
AssetBundle 系统解析
AB 包构建是资源管理的基石。
AB 包压缩方式
| 压缩方式 | 压缩大小 | 加载速度 | 内存消耗 | 适用场景 |
|---|---|---|---|---|
| LZMA | 最小 | 最慢 | 最大 | 首次安装包构建、小体积下载 |
| LZ4 | 中等 | 较快 | 小 | 上线项目(推荐) |
| Uncompressed | 最大 | 最快 | 小 | 大量小文件、频繁加载的情况 |
90% 的项目推荐用 LZ4。LZ4 是唯一同时兼顾加载速度 + 流式加载能力 + 内存占用合理的格式,是线上热更新 AB 包的行业标准。LZMA 最大的缺点是必须整体解压,占据巨大额外内存——虽然构建出的 AB 是最小的,但运行时 Unity 会将整个 AB 原样读入内存再进行一次整体解压,解压后数据也在内存中,结果导致内存占用大、加载时间还长。
AB 包依赖关系
- 将公共资源提取到共享 AB 包
- 避免 AB 包之间双向依赖
- 控制单个 AB 包的依赖数量
AB 包粒度规划
| 粒度 | 优点 | 缺点 |
|---|---|---|
| 细粒度(大量小 AB 包) | 按需加载,内存占用精准 | IO 次数多,依赖管理复杂 |
| 粗粒度(少量大 AB 包) | 加载简单,IO 效率高 | 内存浪费,更新不灵活 |
划分建议:
- 按功能模块划分:UI、角色、场景、配置
- 按更新频率划分:基础包、热更包、活动包
- 按内存生命周期划分:常驻、场景、临时
AB 包加载方式
加载卸载策略决定运行时稳定性。
| API | 说明 |
|---|---|
AssetBundle.LoadFromFile |
从磁盘同步加载 |
AssetBundle.LoadFromFileAsync |
从磁盘异步加载 |
AssetBundle.LoadFromMemory |
从内存数据加载 |
UnityWebRequestAssetBundle |
从网络下载并加载 |
建议本地 AB 包使用 LoadFromFileAsync,网络 AB 包使用 UnityWebRequestAssetBundle,内存敏感场景避免 LoadFromMemory。
AB 包卸载策略
| API | 行为 | 风险 |
|---|---|---|
AssetBundle.Unload(false) |
卸载 AB 包文件,保留实例化对象 | 可能导致资源缺失(Missing 对象) |
AssetBundle.Unload(true) |
卸载 AB 包文件及所有创建的对象 | 可能销毁正在使用的对象 |
建议使用引用计数机制管理 AB 包生命周期,在安全时机(如场景切换)进行清理,并建立 AB 包卸载的自动化测试。
资源引用管理
- 问题表现: 资源无法卸载、内存泄漏、Missing 引用
- 根本原因: 错误的引用持有、循环引用、静态引用
- 解决方案: 建立资源生命周期监控系统;定期进行资源泄漏检测;使用
WeakReference(弱引用,一种不阻止对象被垃圾回收的引用类型)持有资源引用
内存优化与性能监控
内存管理是 AB 包系统的生命线。
内存占用分析
| 内存类型 | 说明 |
|---|---|
| AB 包文件内存 | 压缩的 AB 包数据 |
| 资源对象内存 | 解压后的资源实例 |
| 序列化数据 | 资源在内存中的表示形式 |
监控要点:单个 AB 包大小、同时加载的 AB 包数量、资源实例数量、引用关系复杂度。
加载性能优化
- 预加载: 在场景加载前预加载必要 AB 包
- 异步加载: 避免主线程阻塞
- 分帧加载: 将加载压力分摊到多帧
建议建立 AB 包加载优先级系统,监控加载时的帧率变化,设置同时加载的最大 AB 包数量。
泄漏检测与调试
常见泄漏点:未卸载的 AB 包、静态变量持有、事件监听未移除。建议开发阶段开启详细的 AB 包调试日志,实现 AB 包加载的自动化测试用例,并自定义 AB 包引用追踪系统。
AB 包和 Addressables 的选择
- AB 包优势: 成熟稳定、自定义程度高
- Addressables 优势: 官方维护、功能丰富、工具链完整
若项目已经有完整的 AB 包加载管理机制,可以不用着急替换为 Addressables,Addressables 的本质也只是官方对 AB 包的封装。
混合使用策略
| 系统 | 职责 |
|---|---|
| Resources | 启动必备、无法热更的核心资源 |
| AB 包或 Addressables | 可热更的游戏内容、大型资源、动态资源 |
建议明确各系统的职责边界,建立统一的资源加载接口,避免同一资源在多系统中重复存在。
总结
重点:尽量在项目中使用 AB 包或 Addressables 来整体管理资源加载。
Resources 使用准则:
- 了解其成本,避免滥用
- 建立严格的加载、卸载规范
- 监控 Resources 内存占用
- 制定向 AB 包或 Addressables 的迁移计划
AB 包构建流程:
- 合理规划 AB 包粒度和依赖关系
- 选择合适的压缩方式(LZ4)和构建选项
- 建立版本管理和热更机制
- 实现依赖分析和循环检测
AB 包运行时管理:
- 使用引用计数控制生命周期
- 异步加载避免主线程阻塞
- 安全卸载防止资源缺失
- 监控内存和性能指标
更新与维护:
- 实现增量更新和版本控制
- 建立泄漏检测和调试工具
- 定期优化 AB 包组织策略
- 准备回滚和容错机制
111.2 知识点代码
Lesson111_内存优化_资源优化_AB包和Resources.cs
public class Lesson111_内存优化_资源优化_AB包和Resources
{
#region 知识点一 AB包与Resources资源管理的核心理念
// AB 包(或 Addressables)的使用:
// 实现资源热更新、减少包体大小、按需加载
// Resources 的使用:
// 谨慎使用、避免滥用、了解局限性
// 核心点:
// 项目中尽量使用 AB 包或者 Addressables 管理加载项目资源
#endregion
#region 知识点二 Resources系统解析
// Resources 系统看似简单实则陷阱重重
// 1.Resources.Load 的成本
// 同步加载:主线程阻塞,卡顿根源
// 内存占用:加载后常驻内存,直到明确卸载
// 初始化耗时:首次访问 Resources 文件夹的扫描开销
// 作用:
// 快速原型开发和小型项目使用
// 但不适合中大型项目的主资源管理方案
// 建议:
// 仅用于关键启动资源或编辑器工具
// 绝对避免在运行时频繁调用
// 2.Resources.UnloadUnusedAssets
// 作用:卸载所有未被引用的资源
// 代价:完整 GC 触发,主线程卡顿
// 原理:遍历所有资源,检查引用计数为零的资源
// 建议:
// 在场景切换等自然断点处调用
// 避免在性能敏感时段调用
// 配合 GC.Collect() 使用效果更好
// 3.Resources 内存管理陷阱
// 资源泄漏:Resources.Load 后没有对应 Unload
// 依赖关系:复杂资源依赖导致无法卸载
// 重复加载:同一资源被多次加载,产生多份实例
// 建议:
// 建立严格的加载、卸载配对机制
// 使用引用计数管理资源生命周期
// 监控 Resources 文件夹总体大小
// Resources 使用决策流程:
// 必须使用的资源,启动时预加载 + 引用计数管理
// 尽量不用 Resources 系统
// 频繁使用的资源,使用 AB 包或 Addressables 替代
#endregion
#region 知识点三 AssetBundle系统解析
// AB 包构建是资源管理的基石
// 1.AB 包压缩方式
// AB 分三种压缩方式
// LZMA:压缩大小最小,加载速度最慢,内存消耗最大,使用场景:首次安装包构建,小体积下载
// LZ4:压缩大小中等,加载速度较快,内存消耗小,适合上线项目
// Uncompressed(不压缩):压缩大小最大,加载速度最快,内存消耗小,适合大量小文件,频繁加载的情况
//
// 90% 的项目推荐用 LZ4
// LZ4 是唯一同时兼顾加载速度 + 流式加载能力 + 内存占用合理的格式,是线上热更新 AB 包的行业标准
// LZMA 最大的缺点:必须整体解压,占据巨大额外内存
// LZMA 构建出的 AB 虽然是最小的
// 但运行时 Unity 会将整个 AB 原样读入内存,再进行一次整体解压,解压后数据也在内存中
// 结果就导致内存占用也大,加载时间还长
// 2.AB 包依赖关系
// 将公共资源提取到共享 AB 包
// 避免 AB 包之间双向依赖
// 控制单个 AB 包的依赖数量
// 3.AB 包粒度规划
// 细粒度:大量小 AB 包
// 优点:按需加载,内存占用精准
// 缺点:IO 次数多,依赖管理复杂
// 粗粒度:少量大 AB 包
// 优点:加载简单,IO 效率高
// 缺点:内存浪费,更新不灵活
// 建议:
// 按功能模块划分:UI、角色、场景、配置
// 按更新频率划分:基础包、热更包、活动包
// 按内存生命周期划分:常驻、场景、临时
// 加载卸载策略决定运行时稳定性
// 1.AB 包加载方式
// AssetBundle.LoadFromFile:从磁盘同步加载
// AssetBundle.LoadFromFileAsync:从磁盘异步加载
// AssetBundle.LoadFromMemory:从内存数据加载
// UnityWebRequestAssetBundle:从网络下载并加载
// 建议:
// 本地 AB 包:LoadFromFileAsync
// 网络 AB 包:UnityWebRequestAssetBundle
// 内存敏感场景:避免 LoadFromMemory
// 2.AB 包卸载策略
// AssetBundle.Unload(false):卸载 AB 包文件,保留实例化对象
// AssetBundle.Unload(true):卸载 AB 包文件及所有创建的对象
// 风险:
// Unload(false):可能导致资源缺失(Missing 对象)
// Unload(true):可能销毁正在使用的对象
// 建议:
// 使用引用计数机制管理 AB 包生命周期
// 在安全时机(如场景切换)进行清理
// 建立 AB 包卸载的自动化测试
// 3.资源引用管理
// 问题表现:资源无法卸载、内存泄漏、Missing 引用
// 根本原因:错误的引用持有、循环引用、静态引用
// 解决方案:
// 建立资源生命周期监控系统
// 定期进行资源泄漏检测
// 使用 WeakReference(弱引用,一种不阻止对象被垃圾回收的引用类型)持有资源引用
#endregion
#region 知识点四 内存优化与性能监控
// 内存管理是 AB 包系统的生命线
// 1.内存占用分析
// AB 包文件内存:压缩的 AB 包数据
// 资源对象内存:解压后的资源实例
// 序列化数据:资源在内存中的表示形式
// 监控要点:
// 单个 AB 包大小、同时加载的 AB 包数量
// 资源实例数量、引用关系复杂度
// 2.加载性能优化
// 预加载:在场景加载前预加载必要 AB 包
// 异步加载:避免主线程阻塞
// 分帧加载:将加载压力分摊到多帧
// 建议:
// 建立 AB 包加载优先级系统
// 监控加载时的帧率变化
// 设置同时加载的最大 AB 包数量
// 3.泄漏检测与调试
// 常见泄漏点:
// 未卸载的 AB 包、静态变量持有、事件监听未移除
// 自定义 AB 包引用追踪系统
// 建议:
// 开发阶段开启详细的 AB 包调试日志
// 实现 AB 包加载的自动化测试用例
#endregion
#region 知识点五 AB包和Addressables的选择
// AB 包优势:成熟稳定、自定义程度高
// Addressables 优势:官方维护、功能丰富、工具链完整
// 选择建议:
// 若项目已经有完整的 AB 包加载管理机制
// 可以不用着急替换为 Addressables
// Addressables 的本质也只是官方对 AB 包的封装
// 混合使用策略
// Resources:启动必备、无法热更的核心资源
// AB 包或 Addressables:可热更的游戏内容、大型资源、动态资源
// 建议:
// 明确各系统的职责边界
// 建立统一的资源加载接口
// 避免同一资源在多系统中重复存在
#endregion
#region 总结
// 重点:尽量在项目中使用 AB 包或 Addressables 来整体管理资源加载
// Resources 使用准则:
// 1.了解其成本,避免滥用
// 2.建立严格的加载、卸载规范
// 3.监控 Resources 内存占用
// 4.制定向 AB 包或 Addressables 的迁移计划
// AB 包构建流程:
// 1.合理规划 AB 包粒度和依赖关系
// 2.选择合适的压缩方式(LZ4)和构建选项
// 3.建立版本管理和热更机制
// 4.实现依赖分析和循环检测
// AB 包运行时管理:
// 1.使用引用计数控制生命周期
// 2.异步加载避免主线程阻塞
// 3.安全卸载防止资源缺失
// 4.监控内存和性能指标
// 更新与维护:
// 1.实现增量更新和版本控制
// 2.建立泄漏检测和调试工具
// 3.定期优化 AB 包组织策略
// 4.准备回滚和容错机制
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com