主要包括以下三个方面
1、资源构建与更新框架
1.1资源版本比对方案(版本号、资源清单、各资源文件版本)
1.2构建时参数设置、摘取、替换、上传逻辑(分段构建,打包机内存不足)
1.3运行时流程设计,成功失败判定,异常情况的处理方案,网络问题、存储空间不足、文件缺失、文件损坏情况的应对
1.4文件校验方案CRC,MD5,文件存在
1.5并发下载与后台静默下载方案
1.6资源扩展包相关方案
1.7覆盖安装相关问题(覆盖安装后的加载位置、顺序,unity版本升级导致的ab版本不同问题、清单问题、依赖问题、spriteatlas问题等)
1.8新资源覆盖已加载的旧资源的情况的处理方案(尽量避免,重启或卸载)
1.9热更理想解决方案(散列文件与补丁包的对比、结合,每个邻近版本制作补丁包,兼容散列下载)
1.10构建AB参数对比
lz4速度快,包体大,内存占用低
lzma包体最小,但内存大,整体解压
Uncompressed包体最大,速度最快
AB构建策略,是否可以统一打lzma,再将待拷入包内的ab每个调用RecompressAssetBundle再拷入,实现包内lz4,CDN上lzma,下载时会自动转存为lz4(实测可行)
具体步骤如下
首先AB构建时构建2份,一份BuildAssetBundleOptions.None对应lzma,一份BuildAssetBundleOptions.ChunkBasedCompression对应lz4,打在两个目录,放在包内的部分从lz4的目录拷贝,cdn的部分从lzma的目录拷贝
然后在运行时,下载完ab之后AssetBundle.RecompressAssetBundleAsync(url, url + ".LZMA", BuildCompression.LZ4Runtime);转格式为lz4或uncompressed,再删掉lzma,lzma压缩率高,可节约30%左右的热更下载时间
https://docs.unity3d.com/2022.3/Documentation/Manual/AssetBundles-Cache.html
2、资源加载与卸载框架
2.1AB加载与资源加载对比(同步异步、内存增长情况、卡顿表现)
2.2AB构建策略(大小、多少对比)
2.3资源卸载方式对比,性能对比
3、代码资源更新方案
3.1代码热更方案(lua、ifix、hclr)
3.2相关加密技术
3.3代码热更相关逆向技术(assetstudio、ilspy)
https://github.com/icsharpcode/ILSpy/releases/download/v8.2/ILSpy_binaries_8.2.0.7535-x64.zip
4.资源加载、实例化(包含取消CancellationToken)、卸载(引用计数)全套方案
4.1对于动态实例化的资源(如prefab),由对象池管理实例化对象,ab.Unload(true)释放资源
假设某个关卡,有3个怪物预制体xyz在同一个目录里,打成一个ab叫monster,monster可会依赖一些材质mat、贴图
对象实例化部分
由对象池实例化怪物对象,每种怪物一个小池子,池子空的时候去加载,记录池子内部(已回收)与外部(未回收)的数量(当所有对象均被回收时可销毁该对象池)
Asset加载卸载部分
ab引用计数由其加载的资源路径以及被引用的ab路径共同维护一个HashSet
从monster中load x,则monster的hashset中加入x,计数1,其材质ab mat的hashset中加入monster,计数1
再从mosnter中load y,则monster的hashset中加入y,计数2, 其材质ab mat的hashset不变,因为去重,仍然计数1
卸载时,对象池销毁,若销毁x,monster-1=1仍大于0不卸载,再卸载y,monster再减一=0触发卸载
任意ab(这里是monster)触发卸载后,其依赖的ab(这里是mat)也会递归的触发计数减一
每个ab都会维护一个hashset对应其直接依赖的ab
总结即每个ab维护一个依赖的ab hashset和一个引用计数hashset
4.2对于动态加载的资源(如texture),由asset的cache管理资源的引用计数,同样使用hashset,计数为0时调用Resources.UnloadAsset(asset)来释放资源,
在释放资源后继续触发ab.hashSet引用计数减一
assetCache的引用计数也由hashSet控制,set中存入其生命周期相关的节点信息(如UI界面的assetpath),界面销毁时统一对动态加载模块assetCache做减一
5.ab间循环依赖、循环引用导致无法正确卸载(包括互相引用、三角引用、四角引用等)
举例说明
目录shop中有多个prefab,shopWindow,shopCell,其中shopWindow内引用了activityTab
目录activity中有多个prefab,activityWindow,activityTab,其中activityWindow内引用了shopCell
如果按目录打ab,那么shop.ab与activity.ab就存在循环依赖
以加载shopWindow为例子
shop.ab的hashset中会加入shopWIndow.prefab和activity.ab
activity.ab的hashset中会加入shop.ab
当shopWindow卸载时,shop.ab的hashset中减去shopWIndow.prefab仍剩有activity.ab,count>0导致两个ab均不能卸载
解决这个问题可结合以下两个方案
1.需要规避循环依赖,可编写自动化排查工具
依次遍历每个ab的依赖递归查询是否依赖了自身,并把有问题的ab或asset打印出来
2.预制体之间的引用可以改为弱引用
将引用资源的路径信息挂在预制体上,而不是直接拖上去,不引用guid
暂列提纲,详细内容待补充
浙公网安备 33010602011771号