跳到主要内容

平台特征

内存

WebGL平台由于运行机制和文件系统的特殊性,内存结构与原生App很不一样,通常比原生App消耗更多的内存。下图是同一款游戏以原生App和WebGL运行时的内存对比。

从上图来看,相比原生AppWebGL内存占用多了450MB左右,增大之处主要在于:

  • Wasm的加载与编译多占了约340M
  • Wasm heap中的未分配使用部分多了约90M
  • JS File system占用多了约60M

Wasm文件本身大小有33.8MB,浏览器内核在代码编译执行时会产生更多的内存消耗,相关的缓存、JIT优化也会使用较多内存,总体大约是Wasm文件大小的10倍左右。这一大块内存消耗是原生App所没有的。 另外由于浏览器的沙盒机制,WebGL上无法访问本地文件系统,Emscripten使用JS + IndexedDB模拟了一个文件系统,Wasm访问JS层,JS层再与IndexedDB定期同步,因此JS中始终存有所有文件的一份copy。在微信小游戏中, 应该尽量避免使用Emscripten文件系统。

相比原生app,native heap内存和显存占用也有显著减少,主要原因是纹理压缩格式,InstantGame引擎的优化(il2cpp运行时优化,AutoStreaming)。

WebGL上,Mono Heap由IL2Cpp分配管理,其他native内存(包括引擎Native Heap和其他第三方库如Lua)由Emscripten的malloc分配管理(默认使用dlmalloc) 这两部分都是只增不减,而且相互独立,空闲空间无法共享,因此需要各自都注意控制峰值。

在iOS设备上,WebGL小游戏的内存十分受限,低档机不能使用超过1G内存,高档机的内存上限也在1.4G左右。一旦超过这个限制,就很可能被操作系统触发OOM,重启。 因此微信小游戏的内存优化非常重要。

CPU

CPU性能从公开的benchmark数据,以及我们对比测试的结果来看,wasm比原生app慢了3倍左右。此外Wasm是单线程,并且不支持SIMD,因此WebGL小游戏的CPU性能要比原生低不少。 带来的结果是,原本在App端不明显的性能瓶颈会被放大很多倍,常见的CPU性能瓶颈有解析游戏配置文件,drawcall等等。 另外,原本从多线程和SIMD获益的引擎模块,如Skinning,粒子系统,Culling也会变慢。

WebGL 单帧CPU时间 10.0msIOS 单帧CPU时间 3.55ms

单线程带来的另一个后果是,原本使用多线程或者while循环等待的地方,都会导致游戏卡死。因此需要使用Unity协程或C# async/await改造相关代码逻辑。 下面是一段需要改造的代码示例:

//线程卡死代码示例
var uwr = UnityWebRequestAssetBundle.GetAssetBundle(url);


var asyncOp = uwr.SendWebRequest();
//卡死,单线程,无法跳出while循环,执行异步加载逻辑,asyncOp.isDone始终为false
while(!asyncOp.isDone);


//需要改为协程
yield return uwr.SendWebRequest();

需要注意,C# System.Threading域名下的类和方法,如果底层实现用到了多线程,则无法使用。

GPU & Graphics

GPU性能对比而言,WebGL和原生App的差距不大,仅在将WebGL API和Shader转成平台图形API时有少量额外性能消耗。

但在图形API上,WebGL只支持webgl1和webgl2,大致与OpenGL ES 2.0 和OpenGL ES 3.0功能一致。 延迟渲染和线性色彩空间只有WebGL2.0支持。 有些高级特性和优化无法使用,例如compute shader,也无法使用。因此一些依赖于compute shader的后处理,GPU Skinning等也无法使用。

文件系统

WebGL上无法访问设备本地文件系统,其文件系统由Emscripten使用JS + IndexedDB模拟,用户和Unity引擎通过Wasm读写JS内存中的文件,JS层再与IndexedDB定期同步。Unity引擎默认同步周期为每1000ms一次,因此当文件系统中的文件过多时,容易造成卡顿现象。 另外,由于JS中始终存有所有文件的一份copy,因此会消耗更多的内存。 微信小游戏中切断了JS文件系统和IndexDB的同步,因此不会有卡顿问题,但额外的内存消耗依旧存在,并且游戏退出后文件不会保存下来,应该尽量避免直接读写文件。

无法访问本地文件系统的另一个后果是,原本存放在StreamingAssets文件夹下,可以直接使用文件IO接口同步访问的文件, 在WebGL平台,却是在服务器端。下载这些文件需要时间,因此只能提前下载好,或者改造逻辑使用异步接口访问。

网络

由于安全问题WebGL不支持Socket,因此System.Net.Sockets 和 UnityEntgine.Netwotk中的类都无法在WebGL平台使用,打包时会直接报错。基于Socket实现的HTTP请求需要替换为UnityWebRequest,TCP连接也需要替换为WebSocket, 如UnityWebSocket。 更多网络适配工作请参考微信官方文档网络通信适配

UnityWebRequest基于JavaScript Fetch API实现,在浏览器中运行时,如果访问的服务器未设置允许cross-origin resource sharing (CORS), 则会报类似"Cross-Origin Request Blocked"的错误。需要在服务器的http responses中添加Header "Access-Control-Allow-Origin : * "。

字体

WebGL平台无法使用当前系统的字体,因此当未设置字体,或字体文件不包含中文字符时,将无法显示。推荐使用微信系统字体, 或使用大小在2-3MB,裁剪后的字体文件。