微信小游戏启动时间主要受以下三点影响:
下载小游戏首包数据文件
下载和编译WASM代码
引擎初始化和首场景加载
由于编译WASM的时间也和WASM文件大小相关,因此优化启动速度的关键在于减小小游戏首包数据文件和WASM代码文件大小,以及减少首场景的复杂度。
WASM代码文件大小受引擎和游戏工程C#代码量的影响,用户可以通过以下手段来减少最终打包到游戏中的代码量:
在从ProjectSettings->Player页面Other Settings模块将Managed Strip Level调整到High,配合使用link.xml文件来保留关键C#代码。
开启Strip Engine Code,从而裁剪掉未使用到的引擎代码
在Package Manager中移除或禁用未使用到的package和builtin模块,其中Timeline,Physics影响较大,建议重点关注
删除项目中未使用的插件, 部分插件内会有link.xml文件, 无法通过调整Managed Strip Level裁剪掉
使用宏将微信小游戏平台用不到的代码隔开,例如写出游戏配置文件等仅Editor使用的代码
使用微信小游戏代码分包功能
Player-> Publishing Settings中Debug Symbols选择external
Player-> Publishing Settings中关闭异常,或者选择WASM Exception
打包完成后,可以在Library\Bee\artifacts\WeixinMiniGame\ManagedStripped目录查看哪些第三方插件和引擎模块进入到了游戏首包中。 在类和方法粒度上,可以使用dotPeek之类的工具,打开该目录下的dll来确认是否已经被正确裁剪。
小游戏首包数据文件中包含以下内容:
可以通过以下方法来优化小游戏首包数据文件大小:
Il2cpp metadata的大小和游戏代码量相关,优化WASM代码文件大小的同时也会减小Il2cpp metadata,因此不再重复。
开启CDN的 gzip/br功能,可以明显降低网络数据传输量,减少文件的下载时间。此外开启CDN对后续资源的下载也会有帮助。
在平台特征介绍 内存相关小节中,已经介绍到WASM代码对小游戏内存占用影响非常大。 编译和指令优化、JIT优化消耗的总内存是WASM文件的10倍左右。 因此尽力优化代码大小,对减少小游戏的内存占用非常重要。
纹理资源应使用ASTC格式压缩,从而大幅减少内存和GPU显存占用。对于过大的纹理,可以适当降低分辨率,其原则是保持纹理的分辨率和该纹理被使用时显示在设备屏幕上的分辨率基本一致。
在分辨率不变的情况下,提高压缩的等级,如从ASTC6x6,调整为ASTC8x8甚至是ASTC12x12也可以大幅减少内存。例如近乎纯色的背景图,细节信息非常较少,使用ASTC12x12和ASTC6x6时,视觉上并没有明显区别,但内存占用却减少了3/4。
在同时调整分辨率和压缩等级时,应该优先保证分辨率。 即占用同样内存的情况下,高分辨率高压缩的贴图,比低分辨率低压缩等级的贴图,细节保留更完整。 例如一张贴图的原始分辨率为2048x2048, 应优先将其调整为2048x2048,ASTC12x12,而不是1024x1024, ASTC6x6。
同时Compressor Quality应该调整为100,从而在相同的内存占用下获得更好的纹理质量。该选项会影响Editor压缩纹理时消耗的时间。
压缩后的纹理,在AB中占用的文件大小也会大幅减少,对减少CDN流量使用,改善游戏体验也很有帮助。
对于未勾选Read/Write的贴图,引擎在将其上传到GPU后,便会释放内存中占用的纹理数据。而勾选了Read/Write的纹理,数据则会一直在内存中,导致纹理内存占用翻倍。因此对于所有不需要读写的纹理,都应该取消Read/Write的勾选。
微信小游戏平台不支持TextureStreaming功能,因此Mip Map只有在3D物体的渲染效果改善上有用,无法减少GPU显存占用。对于UI和CubeMap之类的贴图,应该取消勾选Generate Mip Maps,从而减少1/3的内存占用。
AudioClip在解压时,会在JS层占用大量的内存,因此音频的加载类型应该选择Compressed Included Memory。另外强制使用单通道音频,也能在音频播放时节省一半的内存消耗。 大多数情况下,导入音频的Quality选择1 和100,在听觉上并没有什么区别,而音频数据却能大幅减小,因此推荐在微信小游戏平台,将所有音频的Quality都调整为1。 总结而言,音频资源的内存优化方式有:
加载方式使用Compressed Included Memory
勾选Force To Mono,强制使用单声道音频
将Quality调整为1
在普通浏览器中使用时,由于安全保护问题,请勿使用压缩音频,否则可能导致声音播放不正常。
微信小游戏平台上,Mono Heap由Il2cpp分配管理,其他Native内存(包括引擎Native Heap和其他第三方库如Lua)由Emscripten的malloc分配管理(默认使用dlmalloc) 这两部分都是只增不减,而且相互独立,空闲空间无法共享,因此需要各自都注意控制峰值。
Mono Heap峰值的一个典型来源是游戏配置的加载,Native Heap的峰值通常出现在大量AssetBundle加载时。且微信小游戏平台上因为单线程原因,在单帧内无法执行GC操作,因此需要注意单帧的内存分配。
团结引擎对Il2cpp运行时和DynamicVBO池复用做了优化,同时提供的AutoStreaming功能也能避免加载部分未使用的资源,因此使用团结引擎能够对降低内存占用起到帮助。详细信息请前往ReleaseNotes页面查看。
由于微信小游戏平台无法使用文件系统,加载AssetBundle时往往会带来AB文件大小2–3倍的内存开销。因此在使用完AB之后及时释放对减少内存消耗也很重要。 另外在下载AB文件时,应尽量避免使用UnityWebRequest的cache机制,cache下来的文件会通过Emscripten存在JS内存文件系统中,并且没有方法可以主动删除。
对于主动调用文件IO接口写入JS内存文件系统中的AB文件,在使用完成后,也应该主动删除,从而释放AB文件占用的内存。
如果小游戏使用的是builtin管线,并且未使用到HDR,请前往GraphicsSetting中的tier2(微信小游戏平台使用tier2中的设置)关闭默认开启的hdr,可以节省约40MB的显存开销,并且少了一次RT的拷贝操作。
游戏加载过程中,可能会有冗余的资源长期占用内存。冗余资源主要来源以下两方面:
不合理的AB打包机制,导致Shader,Font等资源在不同的AB内重复存在。对于这一情况,需要通过AssetStudio等工具发现冗余的资源,调整AB打包的结构来避免。
加载游戏配置的中间产物长时间存在内存当中。例如游戏将配置文本文件打包到了AB中。启动游戏时,从AB中加载了一个TextAsset,然后从TextAsset中获取了整个文件的长字符串,并将字符串处理成字典等数据结构。 只有最终的字典数据是真实被使用的,而在此之前的加载的AB,TextAsset和长字符串如果未释放,也将在内存中占用不少的内存。微信小游戏平台支持MemoryProfiler package, 因此可以打包development版本并开启Autoconnect Profiler,在游戏启动并连接到Editor后,使用MemoryProfiler抓取内存帧,分析内存冗余情况。
参见 绘制优化
反射调用和字典访问在微信小游戏平台上的性能较低,大量的调用可能会导致游戏卡顿,性能下降,因此在W微信小游戏上应该尽量减少反射调用和字典访问。
Unity WebGL不支持SIMD,且默认不使用多线程,因此CPU的Skinning性能比较低,另外微信小游戏/WebGL平台均不支持Compute Shader,正常的Compute GPU Skinning也无法使用。 团结引擎提供了基于Transform Feedback的GPU Skinning功能, 对于顶点数多的模型,能明显降低CPU消耗,因此推荐在GPU负载低,CPU负载高的游戏中使用。
团结引擎在微信小游戏平台提供了用于优化CPU的Skinning的SIMD支持,开启后可以明显提高CPU的Skinning性能,且没有其他负面影响。
使用Profiler需要保证运行小游戏的手机设备和打包小游戏的电脑处于同一个局域网内。
在微信小游戏页面打包时勾选Development Build“和”Autoconnec Profiler"
完成后打开Window->Analysis->Profiler窗口,等待微信小游戏启动后连接。
用微信扫描开发者工具中的二维码,游戏启动后将自动连接到Profiler
一段时间未使用后,Editor监听将关闭。可以通过重新打包一次或者在引擎安装目录,使用nodejs运行以下命令重新启动: Windows:
"Editor/Data/Tools/nodejs/node.exe" "Editor/Data/PlaybackEngines/WeixinMiniGameSupport/BuildTools/websockify/websockify.js" 0.0.0.0:port localhost:34999
Mac:
./PlaybackEngines/WeixinMiniGameSupport/BuildTools/Emscripten/node/node ./PlaybackEngines/WeixinMiniGameSupport/BuildTools/websockify/websockify.js 0.0.0.0:port localhost:34999 -vv