Unity加入WebGL平台支持以来,Unity开发团队就一直致力于优化WebGL的内存消耗。在Unity使用手册上已有对于WebGL内存管理的详尽分析,Unite Europe 2015与Unite Boston 2015两届大会上,也有专题对WebGL进行深入的讲解。然而,这方面的内容依旧是用户讨论的热门话题,因此我们意识到应当分享更多。

Unity WebGL与其它平台有何不同?
一些用户已经熟悉了部分内存有所限制的的平台。而对于其它如桌面和WebPlayer平台,到目前为止内存还不是问题。
在内存方面,主机平台相对其它平台较为简单,因为可以准确知道内存是如何使用的。这允许您可以很好的管理内存,并保证游戏内容完美运行。在移动平台,内存管理变的有些复杂,因为设备种类繁多,但至少可以选择最低标准的设备,并根据市场情况忽视那些相较于该标准更为的低端设备。

在网页平台,就没有那么轻松了。理想情况下,所有终端用户都拥有64位浏览器和大量内存,但事实却相距甚远。首先,您无法通过任何方法知道,内容所运行的硬件规格。其次,除了用户的操作系统和浏览器外,并不知道其它信息。最后,终端用户可能像运行其它网页一样运行WebGL内容。因此这是一个非常复杂的问题。

FAQ
 
减少内存使用的最佳实践是什么?
简单概括如下:
  • 减少Unity堆的大小

  • 尽可能保持“WebGL Memory Size”足够小

  • 减少代码量

  • 启用Strip Engine Code

  • 禁用异常检测

  • 避免使用第三方插件

  • 减少数据大小

  • 使用Asset Bundles

  • 使用Crunch纹理压缩

 
 
是否存在能够决定最小WebGL Memory Size的策略?
有,最佳策略是使用内存分析器,分析您的内容实际所需的内存大小,然后据此改变WebGL Memory Size。
以空项目为例,内存分析器告诉我们总的使用量仅为16MB(这个值可能在不同Unity版本上有所不同):这意味着只须设置WebGL Memory Size大于16MB即可。当然,内存的总使用量将会依据内容而有所不同。
然而,如果因为某些原因无法使用分析器,可以简单地通过不断地减少WebGL Memory Size 值,直到发现您的内容真正所需要的最小内存使用量为止。
另外非常值得注意的是,任何不是16的倍数的值都将被自动四舍五入(在运行时)为下一个16的倍数,这是Emscripten编译器所要求的。

WebGL Memory Size(MB)设置将决定生成的html中TOTAL_MEMORY(bytes)的值。

 

泰课在线

 

所以,为了在不重新构建项目的前提下,反复测试内存堆的值,推荐使用更改html的方式。一旦您通过此方式发现适合的值,只需在Unity项目设置中更改WebGL Memory Size即可。

最后,记住Unity分析器将占用一些来自Unity堆的内存,所以在使用分析器时可能需要增加WebGL内存大小。
 
 
运行时发生内存溢出,如何修复?
这要看是Unity还是浏览器的内存溢出。这个错误信息将会指出问题所在以及解决办法:“如果您是该内容开发者,请在WebGL设置中为应用分配更多(或更少)的内存。”此时可以据此调整WebGL内存大小设置。然而还有很多可以解决内存溢出的方法。如果出现以下错误信息:

 

泰课在线

 

除了消息内容,还可以尝试减少代码和数据的大小。这是因为当浏览器加载网页时,它将试图为一些内容寻找空余的内存,其中最重要的是:代码,数据,Unity堆和被编译的asm.js。它们可能相当大,尤其是数据和Unity堆内存,这对32位浏览器来说可能是问题。

在一些例子中,尽管存在足够多的空余内存,浏览器仍将加载失败,因为内存是碎片化的。这就是为什么有时候您的内容可能在重启浏览器之后,可以成功加载的原因。
另一种情况是,当Unity 内存溢出时提示以下信息:
 

泰课在线

 

这种情况下,需要优化您的Unity项目。
 
 
如何衡量内存消耗?
为了分析内容所使用的浏览器内存,可以使用火狐浏览器的内存工具或Chrome堆快照。但它们不会显示WebAudio内存使用情况,因此还可以获取火狐浏览器的about:memory页面快照,然后通过搜索“webaudio”找到。如果需要通过JavaScript分析内存,请尝试使用window.performance.memory(只支持Chrome)
使用Unity分析器测量Unity堆内存使用。但请注意,您可能需要增加WebGL的内存大小,以便能够使用分析器
此外,我们一直在致力于开发一个新的工具,以便分析发布版本:使用时先构建WebGL版本,访问http://files.unity3d.com/build-report/即可使用该工具。虽然该工具在Unity5.4中可用,但请注意,这还是正在开发中的功能,并且随时会更改或被删除。至少现在可以使用它达到测试的目的。
 
 
WebGL Memory Size的最小值与最大值是多少?
16MB是最小的,最大是2032MB,然而我们通常建议保持在512MB以下。
 
 
是否可能出于开发目的而需要分配超过2032MB的内存?
这是一个技术上的限制:2048MB(或更多)将会超出TypeArray所用的32位有符号整型的最大值,而TypeArray被用于在JavaScript中实现Unity堆。
 
 
为何Unity堆大小不可改变?
我们一直在考虑使用Emscripten编译器标志ALLOW_MEMORY_GROWTH,来允许调整堆大小,但目前还是决定不用该标志,因为它会禁用一些Chrome中的优化。我们还未对这个影响做一些真正的基准测试。预计使用该标志可能会导致内存问题更严重。如果您遇到Unity堆过小,以至于无法满足所需内存的情况,这时就需要更多内存,那么浏览器就必须分配一个更大的堆,从旧堆中复制一切,然后再释放旧堆。这样做,它需要同时维持新堆和旧堆两份内存(直到完成复制),从而需要更多的总内存。因此,相比使用预定固定内存的方式内存占用更大。
 
 
为什么32位浏览器在64位操作系统上会内存溢出?
32位浏览器运行时的内存限制是一样的,无论操作系统是64或32位。
结论
最后建议使用浏览器专用的工具,来分析您的Unity WebGL内容,因为Unity分析器无法追踪超出Unity堆之外的内存分配。