Memory Considerations when targeting WebGL

构建WebGL目标时的内存考量

Memory in Unity WebGL can be a constraining factor restricting the complexity of the content you can run, so we would like to provide some explanation on how memory is used in WebGL.

对于Unity WebGL来说,内存限制了所运行内容的复杂度。下面我们将解释一下在WebGL中内存是如何被使用的。

Your WebGL content will run inside a browser, so any memory has to be allocated by the browser within the browser’s memory space. The amount of available memory can vary a lot depending on the browser, OS and device used. Determining factors include whether the browser is a 32 or 64 bit process, whether the browser uses separate processes for each tab or has your content share a memory space with all other open tabs, and how much memory the browser’s JavaScript engine requires to parse your code.

因为WebGL内容是运行于浏览器当中的,所以其所需内存都是从浏览器内存空间里分配的。根据所用浏览器、操作系统和设备的不同,WebGL内容可用的内存可能会差别很大。决定因素包括:浏览器是32位的还是64位的,浏览器为每个标签页使用独立的进程还是让WebGL内容和其它标签页使用共享的内存,以及浏览器JavaScript引擎解析WebGL内容代码需要多少内存。

There are multiple areas where Unity WebGL content will require the browser to allocate significant amounts of memory:

在以下几个方面,Unity WebGL内容要求浏览器分配大量内存:

Unity Heap

Unity堆内存

This is the memory Unity uses to store all it’s state, managed and native objects and currently loaded assets and scenes. This is similar to the memory used by Unity players on any other platform. You can configure the size of this in the Unity WebGL player settings (But for faster iteration, you can also edit the TOTAL_MEMORY value written to the generated html file). You can use the Unity Profiler to profile and sample the contents of this memory. This memory will be created as a TypedArray of bytes in JavaScript code, and requires the browser be able to allocate a consecutive block of memory of this size. You will want this space to be as small as possible (so that the browser will be able to allocate it even if memory is fragmented), but large enough to fit all the data required to play any scene of your content.

对于这些内存,Unity用于存储其所有状态、托管的原生对象和当前加载的资源场景。这类似于Unity播放器在其他任何平台上所使用的内存。可以在Unity WebGL播放器设置中配置该内存的大小(为了快速迭代,也可以编辑已写入生成的html文件的TOTAL_MEMORY值)。您也可以使用Unity Profiler对该内存的内容进行抽样和调试。该内存以JavaScript代码的TypedArray字节形式被创建,并要求浏览器能够按其大小分配连续的内存块。我们希望该空间尽可能小(这样当内存零碎时浏览器仍然能够分配该空间),但仍足以容纳播放任何内容场景时所需的数据。

Asset Data

资源数据

When you create a Unity WebGL build, Unity will write out a .data file containing all the scenes and assets needed for your content. Since WebGL does not have a real file system, this file will be downloaded before your content can start, and the uncompressed data will be kept in a consecutive block of browser memory for the whole time your content is run. So, to keep both download times and memory usage low, you should try to keep this data as small as possible. See the documentation page on Reducing File size for information on how to optimize the build size of your assets.

当您创建Unity WebGL构建时,Unity将会输出一个.data文件,其包含WebGL内容所需的所有场景和资源。由于WebGL没有真实的文件系统,所以在开始运行内容之前,.data文件需要先被加载,同时,在内容运行的所有时间里,这些未压缩的文件将一直被保存在连续的浏览器内存块里。为了降低下载时间和内存占用,您应该让这些数据尽可能小。请参见文档降低文件大小,获得优化资源构建大小的相关信息。

Another thing you can do to reduce load times and the amount of memory used for assets is to pack your asset data into AssetBundles. By doing so, you get full control of when your assets need to be downloaded, and you can unload them when you no longer need them, which will free any memory used by them. Note that AssetBundles will be loaded directly into the Unity heap and will not result in additional allocations by the browser (unless you use Asset Bundle Caching using WWW.LoadFromCacheOrDownload, which is using a memory-mapped Virtual File System, backed by the browser’s IndexedDB).

有另外一个方法可以降低资源的加载时间和内存占用,其是将资源数据打包进AssetBundles。这样做,您便能完全控制什么时候加载资源,以及在不需要的时候卸载它们以释放它们所占用的内存。请注意,AssetBundles会被直接加载到Unity堆内存中,而不会造成浏览器的额外内存分配(除非您通过WWW.LoadFromCacheOrDownload使用Asset Bundle Caching技术,该技术采用了基于浏览器索引数据库的内存映射虚拟文件系统)。

Memory needed to parse the code

解析代码所需的内存

Another issue related to memory is the memory required by the browser’s JavaScript engine. Unity will emit very large files of millions of lines of generated JavaScript code, which is an order of magnitude larger than common uses of JavaScript code in browsers. Some JavaScript engines may allocate some rather large data structures to parse and optimize this code, which may results in memory spikes of up to several Gigabytes of memory when loading the content in some cases. We expect that future technologies like WebAssembly will eventually eliminate this problem, but until then, the best advise we can give is to do what you can to keep the size of the emitted code low. See the comments on distribution size here for more information on how to do that.

跟内存相关的另一个问题是浏览器JavaScript引擎所需的内存。Unity会生成包含数以百万行JavaScript代码的非常大的文件,其数量级比浏览器里通常运行的代码量可要大得多。一些JavaScript引擎会分配相当大的数据结构以解析和优化这些代码,某些情况下可能导致加载内容时内存峰值上升到几千兆字节。我们希望未来诸如WebAssembly之类的技术能最终解决这个问题。但在那之前,我们能给的最好建议是尽您所能以降低发行的代码量。请点击这里以查看跟发布大小相关的评论,获得解决问题的更多信息。

Dealing with memory issues

应对内存问题

When you see an error related to memory in a Unity WebGL build, it is important to understand whether it is the browser which is failing to allocate memory or if the Unity WebGL runtime is failing to allocate a free block of memory within the pre-allocated block of the Unity heap. If the browser is failing to allocate memory, then it may help to try to reduce the size used by one or more of the memory areas above (for instance by reducing the size of the Unity heap). On the other hand, if the Unity runtime is failing to allocate a block inside the Unity heap, you may want to increase the size of that instead.

当您在Unity WebGL构建当中看到内存相关的错误,区分以下两点很重要,是浏览器无法分配内存,还是Unity WebGL运行时无法在预先分配好的Unity堆内存块中分配空闲内存。如果是浏览器无法分配内存,那么尝试降低以上内存区域所使用的大小可能会有帮助(比如降低Unity堆内存的大小)。另一方面,如果是Unity运行时无法在Unity WebGL堆内存中分配内存块,则可以相应增加堆内存的大小。

Unity will try to interpret error messages to tell which of the two it is (and provide suggestions on what to do). Since different browsers may report different messages, that is not always easy, however, and we may not be interpreting all of them. When you see a generic “Out of memory” error from the browser, it is likely to be an issue of the browser running out of memory (where you might want to use a smaller Unity heap). Also, you may sometimes see browsers simply crashing when loading Unity content without showing a human-parseable error message. This can have many reasons, but is frequently caused by JavaScript engines requiring too much memory to parse and optimize the generated code.

Unity会尝试分析浏览器错误信息以告诉您是以上两个错误当中的哪个(并给出怎么应对的建议)。因为不同浏览器可能会报不同的错误信息,所以有时分析很困难,无法完全分析。当您看到浏览器产生“内存不足”之类的错误时,可能是浏览器内存用光造成的问题(这时您可能想使用小一些的Unity堆内存)。此外,您有时会碰到加载Unity内容时浏览器直接崩溃,而没有显示可阅读的错误信息。有很多可能原因,但通常是因为JavaScript引擎需要过多的内存以分析和优化产生的代码所导致的。

Garbage Collection considerations

垃圾回收机制考量

When you allocate managed objects in Unity, they will need to be garbage collected when they are no longer used. See our documentation on automatic memory management for more information. In WebGL, this is the same. Managed, garbage collected memory is allocated inside the Unity heap.

对于Unity中的托管对象,当它们不再被使用时,需要做垃圾回收处理。请查看文档自动内存管理,获取更多信息。在WebGL中,也有同样的机制。托管的垃圾回收内存分配于Unity堆内存中。

One distinction in WebGL, however, concerns the points in time when garbage collection (GC) can take place. To perform garbage collection, the GC would normally need to pause all running threads and inspect their stacks and registers for loaded object references. This is not currently possible in JavaScript. For this reason, the GC will only run in WebGL in situations where the stack is known to be empty (which is currently once after every frame). This is not a problem for most content which deals with managed memory conservatively and has relatively few GC allocations within each frame (you can debug this using the Unity profiler).

WebGL中的一个区别在于垃圾回收(GC)发生的时间点。为了实施垃圾回收,GC通常需要暂停所有运行中的线程、检查堆栈和注册已加载的对象引用。而目前这在JavaScript中还不能实现。由此,仅当堆栈为空(目前在每一帧后有一次)的时候GC才会在WebGL中运行。对于保守处理托管内存和在每帧中GC分配相对较少的大多数WebGL内容,这不是问题(您可以使用Unity分析器进行调试)。

However, if you had code like the following:

然而,如果您的代码看起来如下:

string hugeString = "";

for (int i = 0; i < 100000; i++)

{

hugeString += "foo";

}

, then this code would fail running on WebGL, as it would not get a chance to run the GC between iterations of the loop, to free up memory used by all the intermediate string objects - which would eventually cause it to run out of memory in the Unity heap.

则该代码在WebGL中将无法运行。因为在for循环中没有机会运行垃圾回收机制以释放所有中间字符串对象所使用的内存——这些字符串对象最终会导致代码用光Unity堆内存。

链接:

https://docs.unity3d.com/540/Documentation/Manual/webgl-memory.html

构建WebGL目标时的内存考量的更多相关文章

  1. 自制编程语言crowbar(v0.1)构建解析器时分配内存

    crowbar中第一次申请内存是在生成解析器的时候: /* interface.c */CRB_Interpreter *CRB_create_interpreter(void) { MEM_Stor ...

  2. 关于Class对象、类加载机制、虚拟机运行时的内存布局的全面解析和推测

    简介: 本文是对Java的类加载机制,Class对象,反射原理等相关概念的理解.验证和Java虚拟机中内存布局的一些推测.本文重点讲述了如何理解Class对象以及Class对象的作用. 欢迎探讨,如有 ...

  3. 亿级数据时,内存性能低于IO性能

    最近因项目需要,需要生成有0到99999999共1亿的不重复数,于是想着直接将这些数据生成为一个文件就可以了,代码如. private void generate(string savePath) { ...

  4. new对象数组时的内存布局

    #include <iostream> #include <limits> using namespace std; #define SAFE_DELETE(x) \ { \ ...

  5. 实例分析C程序运行时的内存结构

      先验知识 静态变量存储在静态存储区,局部变量存储在动态存储区(栈),代码存放在代码区 寄存器,EBP指向栈底,ESP指向栈顶,EIP指向正在执行指令的下一条指令,三个寄存器中保存的都是地址,32位 ...

  6. Java运行时环境---内存划分

    背景:听说Java运行时环境的内存划分是挺进BAT的必经之路. 内存划分: Java程序内存的划分是交由JVM执行的,而不像C语言那样需要程序员自己买单(C语言需要程序员为每一个new操作去配对del ...

  7. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  8. 了解JVM运行时的内存分配

    了解JVM运行时的内存分配 前言 上文中,在介绍运行时数据区域中的 JAVA 堆时,提到了 JVM 中的堆,一般分为三大部分:新生代.老年代.永久代,本文将进一步了解运行时的内存分配情况. 正文 1. ...

  9. 计算apk包的安装之后占用空间以及运行时占用内存

    1.统计结果如下 计算apk安装占用空间大小方式 为了方式apk包运行时出现缓存数据等对空间计算造成影响.应该先进行安装,然后分别计算空间变化 所有apk包安装完毕后再运行 开启两个cmd窗口 第一个 ...

随机推荐

  1. (Stanford CS224d) Deep Learning and NLP课程笔记(三):GloVe与模型的评估

    本节课继续讲授word2vec模型的算法细节,并介绍了一种新的基于共现矩阵的词向量模型--GloVe模型.最后,本节课重点介绍了word2vec模型评估的两种方式. Skip-gram模型 上节课,我 ...

  2. ubuntu桌面安装常用软件&及常见问题

    自己从windows转向ubuntu桌面开发,根据需求安装以下文件: ubuntu 桌面版下载:http://www.ubuntu.org.cn/download/desktop 有的公司设置静态ip ...

  3. Docker-容器数据卷

    docker容器数据卷相当于外置的移动硬盘 docker容器数据卷主要功能是:容器的持久化.容器间继承+共享数据 特点: (1)数据卷可以容器之间共享或重用数据 (2)卷中更改可以直接生效 (3)数据 ...

  4. Scratch GUI

    原文地址:https://github.com/LLK/scratch-gui/wiki/Getting-Started Getting Started   Bryce Taylor edited t ...

  5. Server runtime

    spring mvc常用的注解: 个介绍. @Controller @Controller 负责注册一个bean 到spring 上下文中,bean 的ID 默认为 类名称开头字母小写,你也可以自己指 ...

  6. JFinal启动报错:Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Connector

    - 错误: Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jetty/server/ ...

  7. cygwin64-安装包管理工具

    1.dos command, install pkg $ setup-x86_64.exe -q -P curl $ setup-x86_64.exe -q -P lynx 2. cygwin64 c ...

  8. Java 封装(内部类)

    1.封装 封装是指,一种将抽象性函式接口的实例细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问.要访问该类的代码和数据,必须通过严格的接口控制 ...

  9. S/4HANA生产订单增强WORKORDER_UPDATE方法BEFORE_UPDATE参数分析

    题目这个增强的输入参数很恐怖,长长的一串: CALL BADI l_badi->BEFORE_UPDATE EXPORTING IT_PIINSTRUCTIONVALUE = IT_PIINST ...

  10. Alpha Scrum3

    Alpha Scrum3 牛肉面不要牛肉不要面 Alpha项目冲刺(团队作业5) 各个成员在 Alpha 阶段认领的任务 林志松:音乐网页前端页面编写,博客发布 林书浩.陈远军:界面设计.美化 吴沂章 ...