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