Unity WebGL内存详解

2016年10月09日 15:49 0 点赞 0 评论 更新于 2025-11-21 20:34

自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的倍数的值在运行时都会被Emscripten编译器自动四舍五入为下一个16的倍数。

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/即可使用该工具。虽然该工具在Unity 5.4中可用,但它仍在开发中,功能可能随时更改或被删除,目前至少可以用于测试。

WebGL Memory Size的最小值与最大值是多少?

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堆之外的内存分配。

作者信息

孟子菇凉

孟子菇凉

共发布了 3994 篇文章