UWA

每天一点UWA:第十周

Posted by 蔡华的博客 on October 5, 2017

AssetBundle

AssetBundle中的脚本

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

如果我用WWW加载了一个AssetBundle,创建了一块WebStream内存。这时候我用另一个东西保存这个AssetBundle的引用,然后用WWW给Dispose了,那么这块WebStream内存会释放掉么?

  • 如果仅是www.dispose,但是AssetBundle引用依然保留的话,那么WebStream是不会释放的。WebStream存在两个引用,一个是www对象,一个是加载出来的AssetBundle。仅这两个引用全部消除时,WebStream才会被Unity引擎回收,具体说明可见之前的技术文章:Unity AssetBundle内存管理机制详解。
  • 5.4之后似乎没有webstream的概念了。因为很多方法现在都是直接从disk读取,或者先保存在读取。

我发现如果不调用UnloadUnUsedAssets这个函数,则无法销毁通过Instantiate实例化出来的材质(包括纹理)。如果我尝试用Resouces.UnloadAsset来卸载挂在GameObject上的实例化材质, 则会闪退,请问这种情况该如何解决呢?

  • 如果想要直接销毁通过Instantiate实例化出来的材质、纹理等资源,则只能使用DestroyImmediate来进行销毁。研发团队可以参考NGUI中UI Draw Call组件里对动态材质的处理,来加深对动态创建以及销毁的理解。

脚本

关于字符串驻留导致的内存占用

  • https://blog.uwa4d.com/archives/USparkle_String-interning.html
  • https://gist.github.com/klkucan/6c51468ca6f92933356477745f0a50e0

Android用AssetBundle.LoadFromFile读取Application.streamingAssetsPath目录下的AssetBundle文件,用什么样的地址?

  • Unity 5.3之前,直接使用 Application.streamingAssetsPath 作为目录路径。
  • Unity 5.3之后,通过新增的LoadFromFile接口加载AssetBundle时,则需要改为 Application.dataPath+”!assets。

准确说这个不是一个优化的问题:NGUI的UIEventListener中的OnPress与UIButton的Press状态不能对应上。具体情况是我点击某个按钮并且按住不放,UIButton处于Press状态,然后移出了Button的范围,UIButton的状态变回了Normal,而UIEventListener中的OnPress并没有监听到,必须松开点击才能监听到。它们的Press状态切换有什么不一样呢?

  • 理论上UIButton的OnPress和UIEventListener的OnPress是在相同时间点触发的,即手指按下和手指抬起这两个时间点上。
  • 而手指在按住状态下移开按钮时, UIButton的状态会变为Normal,这是因为其响应了OnHover的消息。因此如果要模拟UIButton的行为,至少要配合使用OnPress和OnHover两个消息。

模型&动画

求教Mesh导入后这里的uv3和uv4是怎么回事?有的模型只有uv和uv2,有的有四套。

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

物理

伤害检测、还有靠近采集物品时触发可以采集的提示箭头等,我们都使用了碰撞,请问如果不使用碰撞,可以用什么方法代替呢?

  • 使用Trigger也是较为合理的做法,如果想替代,可尝试根据距离、动画运行的时间点来进行判断。

性能综合

prefab加载时依赖图片何时加载

  • 首先说明一下,如果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实例化时的相关资源加载时间。

手动调用UnloadUnusedAssets+GC的问题

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

Resources目录下的所有内容都会加载到内存里吗?如果里面东西多,是不是会导致占用内存过高?

  • 不会,Resources.Load也是即用即加载,但就目前我们统计的结果来看,Resources文件下的资源越多,其生成的ResourceManager内存占用也越大。

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

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

重建的Mesh,Unity引擎会将其重新传入GPU端进行渲染,这部分开销主要体现在Mesh.CreateVBO和Mesh.DrawVBO中。

FK & Statemachine 状态机占用时间比较高,是否有优化的方法呢?

  • 影响该项的因素较多,一般为:
    • 是否开启Optimize GameObjects选项,如果没有,建议开启;
    • 场景中Active的GameObject(使用并开启了Animator组件的)是否较多,数量越多,则该项目开销越高;
    • GameObject的骨骼数越多、AnimationClip的采样次数越多,则该项开销也越高。
  • 因此,建议研发团队可从以上三种情况入手来优化FK & Statemachine的开销。

对Prefab资源的卸载、预览英雄模块、需要卸载英雄角色的资源、动画和材质都可以通过Resources.UnloadAsset(xxx)来顶点清除,而Prefab不行,Prefab 只能用 Destroy + Resouces.UnloadUnused()卸载吗?

  • Prefab如果想要单独卸载,只能使用DestroyImmediate来实现。同时,考虑到Prefab本身已经是很小的一个壳了,对内存的影响非常小,一般情况下是在切换场景的时候一起释放的。