如何优化冷启动的时间

如何优化冷启动的时间

1)UniRx使用心得分享
2)特效是否值得做贴图合并优化
3)AssetBundle LZMA和LZ4压缩
4)iOS渲染相关的闪退问题
5)Shadows.RenderShadowMap的耗时优化


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

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


加载

Q1:第一次启动项目会有冷启动时间过长的情况,请问该怎么优化?

首先肯定是判断游戏在冷启动过程中是在做什么事情消耗了时间,然后针对性地优化。还有就是定义好冷启动的界限,从点击游戏到Unity的闪屏出现这段时间通常定义为冷启动的时间,但是我们项目后来发现在做启动的优化的时候还有很长时间花费在游戏启动之后的一些资源初始化方面。

我在优化启动时间的过程中没有使用什么特别多的工具,主要是基于mlogcat.exe查看设备上输出信息的log,结合自己加入的一些log来做问题的排查。

纯粹的冷启动时间过长,会和Resources目录下的资源有关系,越多越慢。我们是以AssetBundle的方式为主,所以这块注意了下,清理了一些插件引入的确定不需要的资源(直接看打包好的apk里的内容来排查)。另外搜索下还有一些文章说相关问题,可以关注下,这里不赘述。

Unity 冷启动简介
Unity3D游戏如何加快冷启动时间
如何改进Unity3d手游启动速度?
Unity启动耗时优化

说一下我们遇到的游戏启动时间过长时解决过的几个问题。我们定义启动时间是从点击app图标到进入游戏Patch界面(即游戏逻辑接管)这段时间。
1)Shader编译时长。如果只有游戏安装之后第一次启动时间过长,一个很大的可能是shader编译,之后游戏启动因为有了Cache所以会快很多。这种情况的话建议查看下Always Include的Shader内容和变体,使用shadervariantcollection等方案替代。

2)Tolua绑定和Lua资源加载。这种是每次游戏启动都会有的,ToLua接口绑定需要一定的时间,我们在确保前期不会使用Lua的情况下采用多线程的方式进行绑定和加载,保证主线程不会卡住。

3)注意设置Web请求的超时时长。我们在游戏启动的时候做了一些hook的事情,会有Web请求,后来我们遇到一个情况是在很多机器上会黑屏等待30s甚至60s这样的时长,后来发现是因为这个Web请求没有设置超时时间,于是使用了机器默认的超时时间,在不同设备上不同,比如红米2A上会有接近1分钟的超时限制。这个很坑,只是因为那个非必须的Web服务没有正确开启,导致排查了很长时间。
Native层增加界面,减少黑屏等待,提升玩家体验。这个并不能真正解决问题,只是一种缓解手段,等到优化做到位了,其实也就不需要了。
说的内容大都是启动时间而非冷启动,供题主参考。建议题主多看看Unity进程的输出log,可能会有意外发现,通常情况下,不使用Resources的方式的话,在没Bug的情况下冷启动时间应该不会很长,我们因为没怎么用这种方式,所以不是很清楚。这个链接可以参考下:https://www.jianshu.com/p/4366da6dd4a1

感谢贾伟昊@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bf764e8f0d8cc224aa7f4f4


动画

Q2:目前我们是通过Sective(false)放到Pool里,然后用的时候从Pool获取调用SetActive(true)来重新播放动画的。这样做不好的是好像会有一些耗时操作,触发了Animator初始化等;如果不做SetActive操作而是设置Scale为0,可以避免特效继续渲染,但是Animation和Particle会不会一直在运行,同样浪费一些CPU资源。不知道该怎么做会比较好一点?

Animator和Animation所在的GameObject在Activate时确实会有一个比较明显的开销。
Animator.Initialize
Animation.RebuildInternalState

一般来说,如果只是少量粒子特效用到了动画组件,这部分的影响不会特别大,建议看一下这两块的具体消耗占比,如果不高,就可以维持现在的方案。如果这部分耗时比较高,尽可能将动画和粒子系统组件的Transform节点分开,比如在父节点上挂Animator/Animation组件,子节点挂ParticleSystem,在Activate/Deactivate的时候只对子节点进行操作,在父节点上采用Enable/Disable Animator/Animation组件的方式,就可以避免这部分开销。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bf77ad6f0d8cc224aa7f50f


堆内存

Q3:在使用Unity官方的Memory Profiler进行测试的时候发现收集到的ManagedObjectSize和Profiler显示的已使用托管堆的UsedHeapSize差距很大 ,UsedHeapSize是ManagedObject Size的十倍左右,是什么东西没统计到吗?
请输入图片描述
请输入图片描述

我们收到了题主发来的例子,做了下测试。可以复现相近的情况:

Profiler的Used Mono约500KB
Unity 官方的Memory Profiler约50KB
我们用UWA GOT的Direct 模式测了下也是约50KB
所以,只能猜测这相差的约 450KB 是不是Mono内部自己产生的,求证的话得查Mono源码了。另外,这种情况下确实是 “十倍左右”,但建议测试一下堆内存较大时的情况,很可能误差的百分比就很小了的。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bf3a89028a16f55acc3952b


适配

Q4:游戏在其他手机上都正常,但是在小米MIX 2上面默认右边有黑条,需要在手机上开启全面屏设置,但是有一些游戏我没有手动设置也是正确的。请问这个如何默认开启全面屏设置?

在AndroidManifest.xml声明max_aspect值
由于全面屏手机的高宽比比之前大,如果不适配的话,Android默认为最大的宽高比是1.86,小于全面屏手机的宽高比,因此,在全面屏手机上打开部分App时,上下就会留有空间,显示为黑条。这样非常影响视觉体验,另外全面屏提供的额外空间也没有得以利用,因此,这样的应用需要做相关适配。
针对此问题,Android官方提供了适配方案,即提高App所支持的最大屏幕纵横比,实现起来也比较简单,在AndroidManifest.xml中做如下配置即可:
< meta-data android:name=“android.max_aspect” android:value=“ratio_float”/ >
其中ratio_float为浮点数,官方建议为2.1或更大,因为18.5:9=2.055555555……,如果日后出现纵横比更大的手机,此值将需要设为更大。
因此,建议开发者在自己App AndroidManifest的Application标签下面增加下面一段代码:
< meta-data android:name=“android.max_aspect” android:value=“2.1” / >

感谢丁庆@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bf29dfe28a16f55acc39520


Lua

Q5:Lua这边使用function创建一个delegate,然后传入到C#作为事件监听。但是监听结束之后,只是把delegate置空了,并没有释放LuaFunction,就会导致内存泄漏了。有没有好办法解决?
请输入图片描述
如果使用+= 在使用-= 应该是没问题,可以释放LuaFunction。但是业务逻辑的原因,在Lua层不好做到有加有减的操作。最好是能在C#这边就直接把加进来的所有都安全释放。

我们上个项目用了蒙哥介绍的做法。因为FairyGUI没把委托的接口暴露出来(只有class EventListener),所以要修改一些底层代码(改动不大)。
以下介绍一种不用修改源码的实现方式 (测试的确可以释放)
1)Lua DelegateMgr中记录委托被哪些C#对象引用了,并定时清理无用的委托。
请输入图片描述
2)通过覆盖FairyGUI的一些方法, 使Fairy创建的委托纳入DelegateMgr中管理。
请输入图片描述
感谢elemer@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bf10497a1dae055a7c051fe

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

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(原群已满员)