问答 AssetBundle 异步加载资源阻塞主线程的疑问

侑虎科技 · 2020年05月27日 · 895 次阅读

1)AssetBundle 异步加载资源阻塞主线程的疑问
2)Memory Profiler 中 ShaderLab 占用内存大
3)关于 C# 垃圾回收的问题
4)RenderTexture 占用内存过高
5)Unity 2018.4.17f1 异步加载 AssetBundle


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

AssetBundle

Q:请问 AssetBundle.LoadAssetAsync() 这个真的是异步获取资源吗?我用的是个人版 Unity,这个 API 会阻塞主线程,是不是需要专业版才行呢?

A:AssetBundle.LoadAssetAsync() 在加载资源的时候,比如 Prefab,它里面用到的各种 Texture、Mesh 以及 Shader 都会在子线程 Worker 线程中进行加载。但是加载完成后会有后处理,比如 Shader.Parse 是一定会在主线程处理的,Texture 和 Mesh 需要上传到 GPU。如果开了多线程渲染并使用 AUP 功能,非 RW 的 Texture 和 Mesh 的上传会在渲染线程处理;如果没开多线程渲染,那么这一部分还是会由主线程来完成。这些后处理的名字叫 XXX.AwakeFromLoad,如 Texture.AwakeFromLoad,当主线程触发这些回调的时候,主线程其它的 Update 操作就必须等这些后处理完成才能继续。

还有其它的像 Prefab 的序列化,各种 Component 的序列化等也都是在主线程完成的。所以一次 AssetBundle.LoadAssetAsync 操作,其实并不是完全的异步,主线程中依然是要做不少工作。具体细节可以观看 UWA DAY 2019 年的视频,里面的讲解非常清晰:https://edu.uwa4d.com/course-intro/1/91

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


Memory

Q:在真机测试环境下的 Profiler 里查看 Memory 使用情况,发现 ShaderLab 一项占用内存很大,里面主要是什么?

在减少了 Shader 的变体后这部分内存有所下降 ,没有使用 Unity 内置的 Standard Shader。有没有办法在不减少变体的情况下减少这一块占用的内存?

另外,发现同一项下的 Objects 也占用很大。

A1:ShaderLab 是项目在编译 Shader 时产生的解析 Buffer,其内存增长的特点就是 Key words 越多、变体越多,其内存占用越大。目前,还没有看到在不减少变体的情况下,可以减少该内存占用的有效方法。如后续有找到,我们也会来及时更新这块的内容。

97MB 过大了,18.9MB 其实也较大,但可以接受。至于 Objects,建议搜索题库,来查找之前相应的回答,比如:
https://answer.uwa4d.com/search/objects
该回答由 UWA 提供

A2:这个过大是因为某个 Shader 的 Multiple Compile 太多导致的,Multiple Compile 不会进行 Shader 裁剪,例如 Unity 的一个 package,Post Process 的 Uber Shader 就是个典型,我把里边的 Multiple Compile 都换成 Shader Feature,然后用 Shader Variant Collection 只定义需要的分支,一个 Uber Shader 的内存占用从 30m 直接降到忽略不计。但用 Shader Feature 一定要注意裁剪引起的问题,做好预处理。

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


Mono

Q:一个开发中遇到的问题,请教一下,我在游戏一开始有个 Zip 解压资源的操作(大概 150MB 左右的 Zip 包,另开一个线程,非异步操作),解压完之后大概产生了 200MB 左右的 GC Alloc,结束后不手动调用 GC,游戏经过更新场景->登录场景->创角场景->主地图场景(在创角场景到主地图之间有手动调用 GC),进入主地图后 PSS 内存大概 550MB 左右,在 Profiler 里看 Mono 内存,之前解压产生 200MB 没有回收,且后续游戏一直没有回收(每个地图之间切换也有手动 GC,但也没有回收)。

如果我在解压完之后,短时间内手动调用 GC 是可以回收的,Profiler 里面的 Mono 内存回落了,这种情况下进入主地图 PSS 只有 400MB 多一点。总的来说,如果我不及时手动调用 GC,解压产生的 GC Alloc 就会没办法回收,从而常驻内存,这是什么原因呢?

A:Unity 用的 bdwgc 不支持内存移动,猜测是你后续内存分配比较小,填充了之前解压产生的空隙部分,造成了碎片化,导致这些块无法归还操作系统。200MB 的 GC Alloc 过高,建议拿 C/C++ 重写一下。

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


RenderTexture

Q:运行后,就会出现红框里的一些 RenderTexture,但是游戏代码里所有的 new RenderTexture 都打 Log,发现都没有执行到。请问,这些 RenderTexture 可能在什么地方创建呢?该如何优化呢?

A:你这是在编辑器里看到的,真机不会有 SceneViewRT 这些,_TargetPool 这些应该是由于使用了 PostProcessing 这类后处理组件产生的。

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


Editor

Q:为了试试嵌套 Prefab,把工程从 2017 升到 2018,然后 Windows Editor 下就出现奇怪的 AssetBundle.LoadAssetAsync 载入资源不回调的问题,与此同时,使用 LoadAsset 同步加载是没有问题的(真机环境未测试)。

尝试了调整 QualitySettings.asyncUploadTimeSlice 增加时间片及 QualitySettings.asyncUploadBufferSize 增加内存,均不起作用。随机出现部分资源载不到的问题。但是在 PlayMode 下,Editor 中随机打开关闭一些界面 (非游戏界面,Editor 界面),会触发异步加载的完成回调,目前暂时找不到规律。

A:在 Unity 2018.4.18f1 的 Release Notes 中找到一句话:
Asset Pipeline: Fixed an issue where asset bundles could fail to load when using async loading methods. (1215446)

发现是版本问题,将版本升级到 Unity 2018.4.19f1 后,此问题不再出现。

感谢题主王啸予@UWA问答社区提供了回答


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

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