技术分享连载(八十一)

技术分享连载(八十一)

本期话题:打开界面GC过高、动态字体的性能耗时、AssetBundle卸载方法对比、把字体文件裁剪之后对内存和效率的影响是什么、如何优化背包问题...


今天是节后首个工作日,小编又安利了5个营养丰富的技术答疑,让这股知识的清流来缓解下工作上的鸭梨吧!建议阅读时间10分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。
UWA QQ群:793972859
UWA 问答社区:answer.uwa4d.com


资源管理

Q1:我们知道,卸载AssetBundle有两种方式,Unload(true)和Unload(false),一开始我用的是Unload(false),好处有以下几点:

1)开销比Unload(true)小,不太影响体验;
2)对于场景自己的AssetBundle,通常文件本身比较大,可以加载完地图之后直接调用Unload(false);
3)不会销毁正在使用的资源;
4)可以一边加载某些AssetBundle一边销毁另一些AssetBundle,并行处理。

但是实际上用下来,发现会产生资源泄漏问题。虽然代码已经很仔细的检查过了,但还是难免会发生有C#代码引用到某些资源,从而造成AssetBundle释放之后,这些资源释放不掉(UnloadUnusedAssets没用,除非UnloadUnusedAssetsIgnoreManagedReferences)

这个时候我想到了Unload(true),虽然确实可以解决资源泄漏的问题,但产生的问题正好和上面相反:

1)开销大;
2)场景不能加载完之后直接卸载,一边加载一边卸载可能会有崩溃;
3)比较暴力,可能会出现删除正常资源的风险。

请教下大家是如何考虑这个问题的呢?

正如题主所说,两种方法都有各自的优缺点,但就从目前的统计来说,使用Unload(false)的项目占据绝大多数。 就UWA而言,我们比较推荐Unload(false)这种卸载方式,因为Unload(true)过于粗暴,可能会增大删除正常资源的风险。 对于Unload(false)会带来资源泄露的问题,需要研发团队进行更为谨慎的控制。但这种泄露是有方法避免的,题主可以定期定时(如每周)通过UWA GOT线上性能检测来对项目版本进行定制测试,通过场景之间或不同帧之间的资源增量信息来规避资源泄露问题,这种问题越早发现,越容易解决。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59cca2a4430dd9a1336b8b7c


UI 制作

Q2:我们项目中在做UI的时候,需要对选择出来的图片路径加个判断,只有某个路径下的图片才可以选上。通过[CustomEditor(typeof(UnityEngine.UI.Image))]无效。不知道还有没其他的接口可以修改图片的Inspector?

建议题主试试扩展下 Image 组件,比如创建一个 XImage 组件来继承 Image,然后通过 [CustomEditor(typeof(XImage))] 来修改 XImage 的 Inspector。

该问题来自UWA 社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59d9ca49268e715701c74f37


动画

Q3:一个Scroll Rect内有Grid,而Grid下有多个子对象,每个子对象状态使用Animator控制。这个控制在资源工程本地处理无问题,但是在打包加载后出现了刷新问题。具体情况如下:Animator对象在加载并切换状态后,引起了不间断的Layoutrebuild操作,从而引起UI较大的卡顿。这一操作在Disable了对象的Animator脚本后就停止,再开启就继续出现。不知是否有什么解决方案呢?

动作播放停止后,相当于是持续地赋值同一个值,而Recttransform的Scale只要被赋值就会被认为是Dirty的,从而就Rebuild了。所以这种情况只能禁用Animator了。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59cc726a430dd9a1336b8b7a


字体

Q4:我在Unity文档里看到,如果要渲染的字不在字体数据里,Unity最终会去访问当前平台的系统文字。我想问下,把字体文件裁剪之后对内存和效率的影响是什么?

内存: 这时候Unity是会加载系统文字,还是系统文字本身就在系统内存里了呢?这部分系统文字的内存是怎么算的?还是说无法避免呢?

效率: 这边时间消耗是怎么样的?该如何查看?如果在FontNames里写上很多字体,耗时会增加很多吗?

参考的文档:https://docs.unity3d.com/Manual/class-Font.html

我们做了一个简单的例子,在工程里放一个英文字体,且勾选了 Include font data,在 UILabel 中使用。第一种情况是只输入英文,第二种情况是再输入两个中文。连 Profiler 之后的数据分别是下面两张图: image1.png、image2.png,可见 Unity 部分的内存确实是增加了的。但在 Detailed 模式下,两种情况的内存是完全一样的。 说明 Detailed 模式下 Unity 没有统计 Fallback 中系统字体大小,而 Simple 下的 Unity 部分则是统计到了的。所以只能建议题主自行测试一下,通过对比 Simple 模式下的 Unity 部分,来估计下在使用生僻字后,由于系统文字的加载而增加的内存量。

请输入图片描述image1.png

请输入图片描述image2.png

从实验得到的数据来看,只能说在某些情况下可能会增加耗时,比如某一时间点上要创建一大堆生僻字,每个都需要从 fallback 的字体里逐个查找。但这个耗时很难量化,只能建议关注下 Profiler 的 CPU 面板里 Font.CacheFontForText 一项的开销(举个例子,在 UIPanel 重建时 UIPanel.LateUpdate 里会有出现这一项)。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59cf8777c3135d867732308a


性能

Q5:背包一次性加载元素20-25个, GC瞬间达到3MB,电脑瞬间帧数是15帧,请问各位是如何优化背包问题的?
请输入图片描述

首先,从Profiler截图中可以看出,目前的效率是统计是出自于Editor中,而非真机上;其次,CPU耗时较高主要是因为以下几处:
请输入图片描述
(1) BuildPipelineIntefaces.InitializeBuildCallbacks
该项为Unity 5.6以后的新增项, 其在Unity 5.6和2017版本中,均有较高的开销,有网友已经报过Bug,Unity论坛中相关回答说该问题在2017.1f2中被修复,题主可自行核查一下。

(2)各种Awake开销
上图中其他蓝框中可以看出,其他较高的CPU耗时和堆内存分配其实是各脚本的Awake代码造成的,而这些脚本是题主团队缩写的自身代码,绝大部分开销并不出自于Unity引擎API。因此,需要题主对自身代码进行进一步检测,查看其CPU耗时和堆内存分配是否合理。

最后,建议题主在真机上进行测试,因为Editor运行时,在不能完全掌握Profiler中各选项的真正含义时,Profiler往往会起到“误导”作用,耗掉大量的研发时间。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59daf3e0b7f9f3186a45e467


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