Q&A——资源管理(十二)

资源管理

Q1:我们在做依赖打包改进,比如UIAtlas这种脚本,AssetBundle包里脚本没有做依赖,每个包里都有这个脚本,会导致Mono堆内存增大么?对于“脚本也是资产”这一点理解的不是很透彻。脚本在AssetBundle里是不会启动,但是会出现脚本丢失。本身没有做依赖打包的话脚本是冗余在AssetBundle中吧?

首先,需要说明的是,脚本本身的内容是不会被打包到AssetBundle文件中的,AssetBundle文件储存的仅是脚本的索引信息。因此,即便有多个AssetBundle中都存在UIAtlas这一脚本索引,对堆内存也几乎是不产生影响的,且不会产生冗余问题。其次,脚本被当做资源且会产生依赖这一现象,仅在Unity 4.x版本中出现,而在Unity 5.0以后,脚本之间将不会产生依赖关系。因此,如果你目前还在使用Unity 4.x版本进行开发,那么依赖关系打包时确实需要注意这个问题,即依次Push A和B进行打包时,如果AssetBundle之间存在相同脚本,那么B会对A的脚本产生依赖。关于更为详细的分析,请查看我们之前的推送:揭秘AssetBundle 4.x 


资源管理

Q2:我们正在权衡是否对纹理资源进行Alpha通道分离。现在发现,Android低端机上(OPENGL ES 2.0)使用Alpha分离,内存相当是两个ETC1的大小(相对RGBA32是小了很多),但是Shader中纹理采样会执行两次,这个采样其实对低端机消耗还是蛮大的吧?在iOS上分离是没有意义的,而且分离之后使用上会变麻烦,这样权衡之下,分离Alpha只是改善内存的话,优势看起来感觉不太明显,是否有更好的说法来说明分离的优势?

在Android平台上实施Alpha分离操作,是我们非常推荐的做法。如果项目中RGBA32、ARGB32格式的纹理较多,那么研发团队确实需要考虑尽可能将这些纹理转换成两张ETC1格式的问题。不仅内存占用可以降低为之前的1/4,同时加载效率上也会大幅提升。对于不同格式的纹理资源加载效率对比,可以查看我们之前的技术文章:加载模块深度解析之纹理篇。现在纹理的Alpha通道分离操作并不麻烦,网上已经有很多现成的代码可以使用,比如Unity一键图集生成工具。同时,分成两张ETC1纹理确实会增加一次纹理采样操作,但经过大量项目的真机实测,我们并未发现在运行时会出现性能波动。对于iOS平台来说,其PVRTC格式本身已经支持Alpha通道,所以RGBA32/ARGB32格式纹理直接转成PVRTC格式即可。但目前也有不少团队为了使Android和iOS版本开发统一,其在iOS版本上也将其Alpha通道拆开,变成两种PVRTC进行处理。这种做法会增大内存,但好处是开发环境可保持一致,因此研发团队可根据自身情况来考虑是否采用。


资源管理

Q3:如果有一个AssetBundle A内容全是UI用的图片,另外一个AssetBundle B是一个UI的Prefab,在加载UI B的时候我为了节约加载时间,自己手动加载一下AssetBundle A,但是我发现UI B的加载速度并没有加快。所以想请教一下,当从AssetBundle里把这个Prefab GameObject拿出来的时候,它的初始化过程中是从哪儿读这些图片?

这是研发团队平时遇到的较为常见的问题。首先说明一下,如果AssetBundle B和AssetBundle A产生依赖,那么在仅仅加载AssetBunde B中的Prefab B_prefab时,其本身开销仅为B_prefab的加载开销,对于AssetBundle A中的依赖资源并无影响。但是在实例化B_prefab时,Unity引擎会去检查AssetBundle A中的依赖资源是否已经被加载好,如果没有加载好,则先加载AssetBundle A中相关资源,然后再实例化B_prefab。这其实就是大家经常遇到的初次实例化一个技能、角色时出现卡顿的主要原因。因此,如果大家想加快B_prefab的实例化效率,那么对于其依赖关系AssetBundle A中的相关资源,可提前进行预加载,从而减少B_prefab实例化时的相关资源加载时间。


资源管理

Q4:求教Mesh导入后这里的uv3和uv4是怎么回事?有的模型只有uv和uv2,有的有四套。
请输入图片描述

如果在模型导入时就存在 uv2,uv3,uv4,那么这是因为在建模软件中添加了这些顶点属性。一般来说uv3和uv4的使用较为少见,通常是用来配合特殊的Shader实现特殊的效果。而uv2通常被用于Lightmap,uv2可以在建模软件中添加,也可以在Unity中通过Generate Lightmap UVs的选项来生成。

资源管理

Q5:我从UWA的报告中看出我们的GC比较严重,里面有我们自己GC的地方(切换场景的时候),然后就是系统GC的。这个我们无法控制,那么有什么办法优化吗?我发现一个很尴尬的地方,如果我们不自己去GC,内存好像不会返回,但是GC又会引起卡顿。

一般来说,手动调用GC都不太必要,而切换场景时多数情况下会因为堆内存的大量分配导致系统GC的自动触发,但这里的卡顿相对可以接受(只是稍微增加了切场景的时间)。但在非场景切换的时间里,如果系统GC也频繁出现,那么就需要对脚本的堆内存分配进行严格的控制,可以通过查看堆内存分配的TOP10函数,逐个进行分析和优化,减少各个函数的累积堆内存分配量。另外,内存的下降与GC并没有十分的关联。开发者需要注意两点:首先,在Android平台上,GC无法降低Mono部分的总内存(只是把空闲内存变大);其次,Unity部分的内存是通过Resources相关的接口来释放的,GC的操作对这部分内存也没有直接影响(理论上只要引用某资源的GameObject被销毁,那么该资源就能被Resources.UnloadUnusedAssets卸载,因此和GC也没有直接关系)。


资源管理

Q6:场景切换完了后,我们发现上个场景的内容并没有卸载完毕,所以我们调用了Assetbundle.Unload(true)这个函数,紧接着我们调用了UnloadUnusedAssets+GC操作帮我们清理资源(如果不调用后续两个操作的话,我发现内存曲线并没有得到明显下降),而这个时候GC次数又高了,GC次数高了CPU降低,不去GC内存得不到完整释放。我在你们网站上看到说不要开发者频繁去使用UnloadUnusedAssets+GC这个操作,所以希望得到一些帮助。

通过LoadLevel等API来切换场景时,Unity会自动触发Resources.UnloadUnusedAssets的操作,但在切换完成后再次调用Resources.UnloadUnusedAssets来确保卸载完全的做法也是较为常见的,而我们网站上主要是建议开发者不要在其他的时间点来手动调用Resources.UnloadUnusedAssets,在切换场景时还是可以酌情调用一次的,另外对于大场景的MMO类型的游戏,因为切换场景的频率较低,也可以考虑每隔几分钟来手动触发一次Resources.UnloadUnusedAssets来降低内存。而GC的话,则不建议手动调用,即使是在切换场景时。


资源管理

Q7:我们没有使用AssestBundle的方式,使用的都是在Resources路径下的Load,请问Resources目录下的所有内容都会加载到内存里吗?如果里面东西多,是不是会导致占用内存过高?

不会,Resources.Load也是即用即加载,但就目前我们统计的结果来看,Resources文件下的资源越多,其生成的ResourceManager内存占用也越大,研发团队可在Unity Profiler中通过Take Sample来进行查看。


资源管理

Q8:请问下,Unity 5.3.3版本,Android用AssetBundle.LoadFromFile读取Application.streamingAssetsPath目录下的AssetBundle文件,用什么样的地址?

在Unity 5.3之前,安卓上加载 StreamingAssets 目录下的 AssetBundle 时,可以直接使用 Application.streamingAssetsPath 作为目录路径,而Unity 5.3之后,通过新增的LoadFromFile接口加载AssetBundle时,则需要改为 Application.dataPath+"!assets。具体也可参考雨松的博客http://www.xuanyusong.com/archives/4033


资源管理

Q9:Font Texture 资源是如何生成的,因为我发现好像有重复的出现,如何优化呢?

这是Unity为动态字体自动产生的纹理,一般来说不用特别关注。即使重复出现,里面的内容一般也是不一样的(内容即屏幕上显示的文字)。

资源管理

Q10:我们用AssetBundle打包。A包里面有一个界面,C包里面也有一个界面,这两个界面用到了相同的图集,我把图集单独打成了B。游戏实例化的时候,我先加载B,然后加载A,然后手动LoadA里面的一个对象,实例化一个界面。然后释放A和B,后面当需要另外一个界面的时候,我又加载B,然后加载C,然后手动LoadC里面的一个对象,实例化一个界面。现在问题是,B里面的图集,我是不需要手动Load的,这个依赖关系是Untiy去做的,但是按照我之前的做法,B里面的图集会出现2份吗?

按照上述做法,如果之前从A中加载且实例化中的资源没有销毁并且没有调用UnloadUnusedAssets操作的话,B中的图集资源是会出现两份的。其主要的核心点是,AssetBundle B属于公用资源,在后续还有引用的情况下,它不应该被频繁加载和卸载。在第一次卸载A和B时,其由B而加载图集就已经变成了内存中的游离资源,第二次加载B和C时,Unity引擎并不会将B与之前的游离图集资源进行管理,而是再加载一份图集资源出来,这样内存中就形成了两份图集资源。因此,对于这种情况,我们的建议是:

  1. 对于公共依赖的AssetBundle,除非后续有较长时间不再使用,否则不建议加载之后立刻Unload;
  2. 对于由Unload AssetBundle而导致的游离资源,可尝试通过UnloadAsset/UnloadUnusedAssets API来进行清理,但后者需要该资源本身不再被引用;
  3. 通过UWA测评报告中的“资源管理界面”时刻关注每个公用AssetBundle的加载和卸载情况,以免出现频繁加载和卸载的问题。
    请输入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值