问答 Addressable 如何删除旧资源

侑虎科技 · 2020年07月01日 · 1786 次阅读

1)Addressable 如何删除旧资源
​2)Addressable 如何更新 Catalog 文件
3)Editor 在 Android 平台下加载 AssetBundle 的疑问
4)资源被打成 AssetBundle 后,图集被多次加载在内存中
5)Gfx.WaitForPresent 耗时与 GPU 的关系

这是第 209 篇 UWA 技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间 10 分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

Addressable

Q1:目前计划使用 Addressable 来实现资源热更新,实际真机测试发现当资源更新后,旧的资源 Addressable 并不会把它删除,同时可以看到 App 占用的数据文件会越来越大。请问有什么办法可以把指定的 Group 或 Label 的资源删除吗?

试了 Addressable.ClearDependencyCacheAsync 也不行。实际测试这个接口只能删除最新版本的资源。当本地已经是最新版本资源时这个接口确实有效;但是如果本地需要更新资源时,这个接口应该也是尝试去删除最新资源,然而本地并没有最新版的资源,所以大概就无效了。

A:调用 Addressable.ClearDependencyCacheAsync 实质是调用了 “Caching.ClearAllCachedVersions();”。事实上是使用了 Unity 的 Caching 系统。

在 Windows 编辑器环境测试了一下。
Caching 的目录为 “C:\Users\UserName\AppData\LocalLow\Unity\ProjectFolder”,当正常下载 AssetBundle 以后,该目录内就出现 “stage01_298bd883434eedb69ea7316cb23e0b0d\662ab7a0d2aa99bc7a2dbb7baec63872” 之类的目录,并保存着当前的 AssetBundle 版本,当更新 AssetBundle 并执行下载以后,该目录也会出现其他 AssetBundle 的 Caching 目录。

在执行下载之前,先执行了一下 “Caching.ClearCache();”,这时会发现 Caching 目录内已经被清空,所有版本的 AssetBundle 都没有了。下载完成后,该目录只保留了最新的 AssetBundle 资源。由此可推,即使不通过 Addressable 系统,仍然可以通过 Caching 把所有的资源都清理掉。

于是继续进行第二个实验,连续更新几次 AssetBundle 以后,Caching 目录内已经有多个版本的 AssetBundle 目录了,当有新的更新后执行 “Addressables.ClearDependencyCacheAsync(key);”,发现的确并没有将旧版本的 AssetBundle 都删除。因为 “Caching.ClearAllCachedVersions” 的参数是对应的 AssetBundle 名字,而 Addressables 的管理 AssetBundle 包名是带 Hash 的,因为每个版本的 AssetBundle 文件名都不一样的,Caching 系统也就无法分辨了。

继续做实验,将打包名字去掉 Hash,Caching 目录内的 AssetBundle 目录名也不带 Hash 了,然后连续更新几个版本后发现,该 AssetBundle 目录内多了几个不同 Hash 版本的目录,内部才是真正的 AssetBundle。于是走 “Addressables.ClearDependencyCacheAsync(key)”,这时就能正确地删除旧版本,然后再更新新版本了。

Q2:确实不勾选 Hash 打包可以成功删除了,这种方式貌似就是覆盖式的打包,不知道会不会有其他隐患,目前来看够用。

A:隐患就是如果按照 Label 来做更新检查,本来可以只下载差异部分,但是因为同样使用 Label 做清除 Caching 的工作就会造成重复下载原本不必要更新的部分。于是就需要遍历所有的 Location 然后去检查更新,并将有更新的 AssetBundle 放入列表,然后再依次清除旧缓存,重新下载。这样就和传统方案没太大区别了。

Q3:请问下不勾选 Hash 其实就不用清除了吧?名字一样不是会直接覆盖吗?

A:不勾选 Hash,只是在 Cache 的目录内第一级资源同名子目录是一致的,但是里面保存具体数据的子目录是递增的,因为有不同版本。每个版本都会有一个子目录。这个是 Caching 系统管理的。

感谢黄程@UWA问答社区提供了回答

Addressable

Q:项目使用 Addressable 做资源管理,资源更新方面因为原来有一套下载更新流程,就不使用 Remote 功能,全部 Group 都是 cannot change post release。只是单纯用 Addressable 打包,然后比较差异下载回本地,使用 “Addressables.InternalIdTransformFunc” 指向新资源的路径。

但是由于下载回来新的 Bundle 的 crc 跟原始 Catalog 的 crc 不一致,会报错 “CRC Mismatch. Provided 16302c0b, calculated 17167beb from data. Will not load AssetBundle”。

希望在下载完资源后重新加载新的 Catalog 文件,应该怎么实现?尝试使用了 “Addressables.LoadContentCatalogAsync” 接口加载下载回来的 Catalog 文件,但是还是报错。

A:使用 “Addressables.LoadContentCatalogAsync” 后还是出错的可能性有一种:因为默认的 Catalog 对应的 Locator 并没有移除,造成查找时首先在默认的 Locator 内找到资源,而因为不走 Addressable 的更新流程,那么默认的 Locator 对应的 crc 永远就是旧的,于是出错了。

尝试启动后使用 “ClearResourceLocators()” 或者 “RemoveResourceLocator(Addressable.ResourceLocators[

感谢黄程@UWA问答社区提供了回答

Rendering

Q:Unity Editor 下加载 AssetBundle,材质球 Keywords 正常,但是某些属性不存在。
Unity 2018.4.23f1 Android 版本,Shader 用的是新建的 SurfaceShader,Shader Stripping 设置如下图。

Mat、Shader、Prefab 打在同一个 Assetbundle 上,在 Editor 中运行加载该 Assetbundle 上的 Prefab,会发现一些属性不存在,而原本挂在这个场景中的 Prefab,则是正常。




A:打包成 APK 后连接 FrameDebugger 看到在场景中的球和 AssetBundle 加载后实例化的球的 Shader 参数信息完全是一样的,所以可能是在 Android 平台 Build 后的 AssetBundle 在 Editor 中加载才会出现楼主所说的问题。


另外再做了一个对比试验,将平台切换成 PC。在编辑器里,场景中原有的球和 AssetBundle 加载出来的球的渲染就是完全一样的了。

感谢 Xuan@UWA 问答社区提供了回答

AssetBundle

Q:资源被打成 AssetBundle 以后,发现图集被多次加载在内存中,这正常吗?

若是不正常,是什么原因造成这个问题的呢?怎么解决?(Unity 版本是 2017.3.9)

A1:可能是在通过 AssetBundle.Unload(false) 卸载 AssetBundle 对象后,重新创建该 AssetBundle 对象并加载之前加载过的资源到内存,这样就出现了冗余。还有一种就是打包时出现了冗余。

感谢李星@UWA问答社区提供了回答

A2:根据经验说说造成这种情况的原因。

  1. 确认打包的时候,图集是依赖的打包,而没有被打包到各个 prefab 里面。这个推荐使用 UWA 的在线 AssetBundle 资源检测工具,直接把整个项目的 AssetBundle 上传,可以查出很多问题。

  2. 你把 Assetbundle 包给卸载了。AssetBundle.Unload(false),这样 Assetbundle 关联断了,就会重新加载资源,如果楼主用的是 LZ4 的压缩格式,不推荐再去调用 Unload(false) 了,第一 LZ4 的 ab 包本身占用极少的内存,第二 Unload(false) 的资源多了,调用 Resources.UnloadUnusedAssets 接口,容易造成卡顿。应该自己写引用 AssetBundle 计数,直接 Unload(true)。

感谢简单就好@UWA问答社区提供了回答

A3:根据经验有以下几点供参考。

  1. 使用 Unload(true) 更好一些。经常会有人操作不规范挂住一些资源,然后越积累越多,主动释放安全很多。

  2. Unload(false) 会导致再次加载同一资源被开一个新的区域。某些重复利用率较高的资源,会出问题。比如,材质 A 和材质 B 都引用一个贴图,加载材质 A 根据依赖加载贴图,然后释放 AssetBundle;加载材质 B 时,会加载第二份贴图。所以用 Unload(false) 并不能达到及时释放 ab 的效果。

  3. 反复加载的问题。卸载 AssetBundle 之后,再次使用尚未析构的资源,又需要重新加载 AssetBundle,虽然 LZ4 的加载速度可以忽略不计。

感谢欧月松@UWA问答社区提供了回答

Rendering

Q:请教一下,在报告中看到 Gfx.WaitForPresent 很高,是不是就说明 GPU 压力很大?CPU 均值在 19ms 左右,是不是说明压力在 GPU 端而不是 CPU?是否应该先去优化 GPU?

A1:Gfx.WaitForPresent 的值高一般是开了多线程渲染,要么在做垂直同步,要么 GPU 负担较重,CPU 已经做完了等着 GPU 完成做呈现。建议查一下具体渲染的内容,或者在 Profile 内看看渲染线程的工作情况。

参考文章:《扒一扒 Profiler 中这几个 “占坑鬼”》

感谢黄程@UWA问答社区提供了回答

A2:Gfx.WaitForPresent 就是 GPU 瓶颈:

  1. 降分辨率;
  2. Shader 优化,优化指令,高中低配使用不同的 Shader LOD;
  3. 做视距控制,不光减 DrawCall,不透明物体同样存在 Overdraw,特别是场景复杂度高的情况下。

感谢 BQ 哥@UWA问答社区提供了回答

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在 UWA 问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之 “石”,也能攻你之 “玉”。

官方技术 QQ 群:793972859(原群已满员)

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册