Backtrace Blog
For the latest developments from our engineering team, head over to the Engineering Blog at engineering.backtrace.io.
Memory and Performance Issues in Unity WebGL Builds
There are many challenges involved in developing apps and games for WebGL builds in Unity. One of the major challenges that Unity WebGL developers face is to avoid performance issues that could lead to a negative gaming experience. This blog explores the best practices and strategies pertaining to the performance of Unity WebGL builds and identifying and dealing with issues that lead to a WebGL app running out of memory (OOM).
There are many challenges involved in developing apps and games for WebGL builds in Unity. One of the major challenges that Unity WebGL developers face is to avoid performance issues that could lead to a negative gaming experience. This blog explores the best practices and strategies pertaining to the performance of Unity WebGL builds and identifying and dealing with issues that lead to a WebGL app running out of memory (OOM).
Memory Constraints in WebGL
The complexity of the content that the Unity WebGL apps can run in a web browser is primarily constrained by memory. The browser allocates the memory in its memory space that your app needs to run your content and the amount of available memory varies depending upon various factors such as the type of device, the type of operating system, the type of browser and whether it is a 32 bit or a 64 bit browser, to name a few. The Unity WebGL app requires the web browser to allocate plenty of memory in certain cases.
The Asset Data File
Unity generates a .data file whenever you build a WebGL game. This data file contains all the assets and scenes the game requires at the time of launch.
As Unity WebGL builds can’t access the real file system, they create a virtual memory file system (VMFS) in which their .data files are extracted. This memory file system is allocated in the browser's memory space by Emscripten and the browser retains the uncompressed data file during the game’s runtime. Therefore, a WebGL game with a complex 3D scene involving many assets may slow down and potentially risk running out of memory.
Reducing memory use by using Asset Bundles
It is clear that WebGL builds require efficient management of memory and in order to reduce the uncompressed data file during your app/game’s runtime, you will need to reduce the data file size. The techniques applicable to build platforms on mobile devices can be applied here too. Asset Bundles can be used effectively to manage memory allocation.
It is even more crucial in the WebGL platform to use Asset Bundles because they load directly into Unity Heap and require no extra allocation by the browser. Additionally, they can be loaded and unloaded on demand and they free up memory on unloading.
The Unity Heap
A common feature to all build platforms in Unity is that every runtime object is stored in a memory heap that Unity calls ‘Unity heap’ or ‘Unity memory heap’. These run time objects include native objects, assets that are loaded, scenes, shaders, animations as well as other managed objects.
It is worth noting that this heap is one contiguous block of allocated memory. Until a few years ago, you had to allocate the maximum size of the heap in the project build settings but now Unity supports automatic resizing of the heap to adjust to the needs of the game, and is expandable up to 2GB.
This resizing feature however, can often cause your WebGL game to crash, especially in cases where the browser fails to allocate one contiguous block of memory. And this is exactly why it is very important to keep the heap size as small as possible.
Garbage Collection (GC)
The last important consideration with regards to Unity WebGL builds is the Garbage Collection (GC). Typically, the GC locates and collects unused memory and then reallocates it in the Unity Heap. On non-WebGL platforms, all running threads are paused to give time for the GC to check the stack but due to limitations in Javascript, this is not possible in WebGL builds.
The primary condition for the GC to run on WebGL is that the stack must be empty. This is why GC runs once after each frame is rendered, as this is when the stack (which is a part of the Unity Heap) is empty.
The following code will work fine in non-WebGL builds because the GC would get a chance to get invoked in between iterations of a loop to clean up the memory used by the intermediate string objects but it could run out of memory (OOM) in a WebGL build:
Example: The above for-loop could result in an out-of-memory error
Even if you do not run into OOM (Out of memory) issues, it is always a good practice to avoid concatenating strings unnecessarily. In the following example, a countdown timer is continuously updated but the code on the left uses a string concatenation to concatenate the prefix with the countdown time. The code on the right is rewritten to avoid concatenation and therefore avoids memory allocation in intermediate string objects, which over time would result in unnecessary garbage collection and performance bottlenecks.
Best Practices to avoid out-of-memory issues involving GC
The following best practices can be adopted to reduce garbage collection and potential out-of-memory issues arising from the lack of garbage collection in between frames in a WebGL build:
Using Backtrace to detect errors and exceptions
Backtrace allows developers to integrate crash handling into their apps, capture and monitor errors, prioritize issues to work on, and get everything they need to debug the problem in a single interface.
While the techniques mentioned in this blog will help you to design better apps and games that reduce the likelihood of them running out of memory (OOM), there might be situations where you might encounter other types of errors and exceptions. In those situations, Backtrace makes it easy for Unity WebGL developers to collect errors/exceptions and report them in real-time. It is very easy to integrate Backtrace into your Unity WebGL project. Please refer to our documentation here to learn how easy it is to get started with Backtrace.
TRY IT TODAY!
Backtrace is a Unity VSP (Verified Solution Partner). Learn more about how we work with Unity and sign up for a free trial today:
https://backtrace.io/unity/