Memory in Unity WebGLA JavaScript API that renders 2D and 3D graphics in a web browser. The Unity WebGL build option allows Unity to publish content as JavaScript programs which use HTML5 technologies and the WebGL rendering API to run Unity content in a web browser. More info
See in Glossary 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.
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.
There are multiple areas where Unity WebGL content will require the browser to allocate significant amounts of memory:
This is the memory Unity uses to store all its state, managed and native objects and currently loaded assets and scenesA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info
See in Glossary. This is similar to the memory used by Unity Players on any other platform.
The Unity heap is a contiguous block of allocated memory. Unity supports automatic resizing for the heap to suit the needs of the application. The heap size expands as an application runs, and can expand up to 2GB. Unity creates this memory heap as a Memory object. The Memory object’s buffer property is a resizable ArrayBuffer that holds the raw bytes of memory accessed by WebAssembly code.
Automatic resizing of the heap can cause your application to crash if the browser fails to allocate a contiguous memory block in the address space. For this reason, it is important to keep the Unity heap size as small as possible. Therefore, be mindful when you are planning the memory usage of your application. If you want to test the size of your Unity heap, you can use the ProfilerA window that helps you to optimize your game. It shows how much time is spent in the various areas of your game. For example, it can report the percentage of time spent rendering, animating, or in your game logic. More info
See in Glossary to profile the contents of the memory block.
When you create a Unity WebGL build, Unity generates a .data
file. This contains all the Scenes and Assets the application needs to launch. Because Unity WebGL does not have access to the real file system, it creates a virtual memory file system, and the browser unpacks the .data
file here. The Emscipten framework (JavaScript) allocates this memory file system in the browser memory space. While your content runs, the browser memory keeps the uncompressed data. To keep both download times and memory usage low, try to keep this uncompressed data as small as possible.
To reduce memory use, you can pack your Asset data into AssetBundles. AssetBundles allow you full control over your Asset downloads. This means that you can control when your application downloads an Asset, and when the runtime unloads it. Unloading unused Assets frees up memory.
AssetBundles download directly into the Unity heap, so these don’t result in extra allocation by the browser.
Enable Data Caching to automatically cache the Asset data in your content on the user’s machine. This means you don’t need to re-download that data during later runs. The Unity WebGL loader implements Data Caching with the IndexedDB API. This option allows you to cache files which are too large for the browser to cache natively.
Data caching enables the browser to store application data on the user’s machine. Browsers often limit the amount you can store in their cache and the maximum file size that can be cached. This is often not enough for an application to run smoothly. Therefore the Unity WebGL loader implements Date Caching with the IndexedDB API. Instead of storing the content in the browser cache, Unity stores the data in the IndexedDB.
To enable the Data Caching option go to File > Build Settings > Player Settings > Publishing Settings.
Your server can emit the Large-Allocation HTTP header for your content. This tells supported browsers (currently only Mozilla Firefox) about your memory needs. This information allows the supported browser to spawn a new process using unfragmented memory space. The browser can also do extra housekeeping to make sure the large allocation succeeds. This can solve issues where the browser runs out of memory when trying to allocate the Unity heap. This is especially important on 32-bit browsers.
Garbage collection is the process of locating and freeing up unused memory. Once the garbage collector collects unused memory it reallocates it inside the Unity heap.
For an overview on how Unity garbage collection works, see Automatic Memory Management. WebGL garbage collection runs when the stack is empty. The stack is a part of the Unity heap but not the heap itself. This usually occurs after every frame. This is different from the garbage collection process on other platforms, where the collector pauses all running threads so it can inspect the stack. This is not possible in JavaScript. You can debug the garbage collection process using the Unity Profiler.
On most other platforms garbage collection pauses all running threads. The garbage collector will then inspect their stacks and register for loaded object references. This is not currently possible in JavaScript. For this reason, the garbage collector will only run in WebGL in situations where the stack is empty. This currently happens once after every frame.
Due to this, the following code would fail running on WebGL. This is because the collector does not get a chance to run the garbage collector between iterations of the loop. This means the garbage collector cannot free up memory that the intermediate string objects use, and is likely to run out of memory in the Unity heap.
string hugeString = "";
for (int i = 0; i < 100000; i++)
{
hugeString += "foo";
}
2018–08–23 Page amended