Unity 性能优化 之 打包优化( 耗电量 | 发热量 | 启动时间 | AB包)
Unity 性能优化 之 发布优化
- 移动端耗电量与发热量概述
- 常规负载优化
- 非常规优化
- 启动时间
- iOS平台启动时间优化
- Andorid平台启动时间优化
- Unity初始化优化建议
- 打AB包优化
- AssetBundle
- AssetBundle打包方案
- 构建AB参考策包略
- 构造AB包值得注意的点
移动端耗电量与发热量概述
- 通过平台对应工具确保设备电池处于健康状态;
- 通过UPR等工具确保能对工程的耗电量、发热量进行正确分析;
往往设备会存在温度墙,当温度过高时,设备将为芯片降频,从而导致工程性能被迫下降从而降温;
常规负载优化
- 对于目标60fps,则需要控制CPU开销在10-12ms、GPU开销在6-8ms;
- 对于目标30fps,则需要控制CPU开销在18-20ms、GPU开销在8-10ms。
非常规优化
- 网络与IO相关:如发包频率和IO读写频率;
- 显示亮度与显示帧率相关:如主动降低屏幕亮度或动态控制分辨率,并通过OnDemandRendering控制帧率方法;
- 三方库相关:如Wwise,将混合音乐控制在4个以内;如Criware,建议不要在移动端使用,或不要频繁使用;同时注意检查平台SDK;
启动时间
启动时间分为两段:
- 黑屏至UnityLogo的时间;
- UnityLogo至场景出现的时间。
iOS平台启动时间优化
iOS平台Unity程序启动流程分为PreMain、Main和StartUnity三个过程。
其中PreMain和StartUnity过程可以被优化,Main过程需要修改Unity源码才能做修改。其中Main过程的结束表现为UnityLogo的出现。
iOS平台程序启动需要注意的点:
- 不同版本的iOS系统程序启动时间略有差异;
- iOS启动分为首次启动、冷启动与热启动,一般所涉及优化为冷启动;
- 启动时间超过20s的程序会被系统自动杀死进程;
- 默认竖屏程序会比默认横屏程序启动时间略长;
- 推荐PreMain时间最好不要超过400ms;
- iOS15以后通过Xcode的Timeline功能可以查看整体启动过程。
iOS在PreMain阶段优化建议:
Andorid平台启动时间优化
Andorid平台Unity程序启动流程分为创建APP进程、APP进程创建后和Startup三个过程。
类似iOS,前两个过程为APP初始化,其表现为UnityLogo的展示,StarUp过程表现为第一个场景的加载完成。
Android启动优化建议:
- 减少Activity OnCreate函数中复杂的逻辑工作;
- 将所有的资源初始化做LazyLoad放到不同的线程中,不要全部放到主线程中。
Unity初始化优化建议
Unity初始化完成到第一个场景加载完成优化建议
- 尽量不要使用Resources目录,即使使用也不要有过多资源;
- 第一个场景尽量保持简单,挂载脚本不宜过多,Awake/Start的逻辑尽量简单;
- 资源Text模式比force binary模式慢很多;
- Graphics下Always Include下不宜包含太多或太复杂的Shader脚本;
- 要做Shader变体剔除,变体过多的项目不要使用Shader.WarmupAllShaders来做ShaderCache;
- ab包不宜打得过碎,尽量使用LZ4压缩,不要使用LZMA压缩;
- 注意,编辑器下InitializeOnLoad、InitializeOnLoadMethod属性,运行时RuntimeInitializeOnLoadMethod等属性,这些属性标记的函数如果过于复杂,也会影响编辑器启动与Player启动的速度。
打AB包优化
AssetBundle
- AssetBundle是一个存档文件,包含运行时加载的特定平台的非代码资源(纹理、模型、音乐、Prefab、Scene等),以及资源之间的依赖关系。
- AssetBundle可以用于资源更新,减小安装大小,针对平台加载优化资源,减轻运行时内存压力。
- AssetBundle是一个容器,包含存档文件包头、以及序列化类型文件与资源文件。
AssetBundle打包方案
- 通过BuildPipeline接口直接打包,并通过对应回调进行功能的拓展,同时可以结合Asset Graph处理整体流程。
- 通过ScriptableBuildPipeline接口进行实现,同时可以结合Addressables包完成更多分包策略。
构建AB参考策包略
- 根据对象的修改频率差异拆分不同的AssetBundle;
- 具有相同生命周期的资源打成一个AssetBundle,如果一个AB中只有不到50%的资源经常加载,可以考虑拆到不同的AssetBundle中;
- 不可能同时加载的高低配置资源拆分到不同的AssetBundle;
- 如果多个对象依赖于某个AssetBundle中的单个资源,这类单个资源可以单独打包或者根据生命周期将这类被多个对象依赖的资源打成共享AssetBundle;
- 如果一组对象只是一个对象的不同版本,可以考虑使用AB变体(注意Addressable不支持AB变体)。
构造AB包值得注意的点
- AB包体不能因为避免重复引用而拆的过于细碎,过小的包体,会导致包头占用内存压力会比较大(2M~5M的包体是一个合理的参考值);
- LZMA格式压缩的AB包较小,但需要完全解压后再加载,加载时间更长,而LZ4格式压缩的AB包按块加载,加载时间较快,但包体大小较大(移动平台建议使用LZ4压缩格式);
- 如果确定使用相同版本Unity发布打包,即后续开发不会升级Unity版本,那么AB包体不做Unity版本兼容时可以尝试开启打包选项中的BuildAssetBundleOption.DisableWriteTypeTree选项, 这样处理版本兼容的TypeTree信息不会被打到AB中,可以极大减小包体大小及运行加载时的内存开销;
- 避免同一个资源被打入多个AB中,会增加运行时内存开销,可以使用UPR Assets Checker工具来做检查;
- 不要使用AB包文件的MD5值作为更新包依据,一般会使用包内资源的MD5值或路径作为判断包是否发生变化的依据。
本文整理自:Metaverse大衍神君《Unity性能优化》