Quick answer: Enable Memory Growth in Player Settings > WebGL > Publishing Settings, set Initial Memory Size to 256–512 MB, compress all textures with Crunch or ASTC, and strip unused code via IL2CPP Code Stripping High. If still failing on mobile, show a “desktop recommended” notice.

Here is how to fix Unity WebGL build memory out of bounds. You export a WebGL build, upload to itch.io or host on a website, and the game shows a loading bar that freezes at 80% with a red error: “memory access out of bounds” or “Uncaught RangeError: WebAssembly.Memory(): could not allocate memory.” Or it loads fully, plays for a minute, then crashes with the same message. The error message is cryptic, the browser console is useless, and there is no stack trace pointing at your code.

The Symptom

Browser console shows one of:

Desktop Chrome and Firefox are the most tolerant. Safari, iOS Safari, and older Android browsers fail earliest. Reproducing only on certain machines is a strong indicator of memory limits.

What Causes This

Fixed heap too small. WebGL builds allocate a fixed-size WebAssembly heap at startup. If Unity asks for more memory than the heap size, allocation fails — and in WebAssembly, an out-of-bounds write doesn’t just “corrupt memory,” it terminates execution immediately.

Memory Growth disabled. Without Memory Growth, the heap is fixed. With it, the heap can grow at runtime up to a maximum (2 GB on most browsers, 4 GB on desktop Chrome/Firefox with 4 GB memory flag).

Large uncompressed textures. Textures that live in memory consume large amounts of heap. A 2048x2048 uncompressed RGBA32 texture is 16 MB in memory — 100 of those is 1.6 GB. Crunch compression for ETC2/ASTC cuts memory by 3–4x.

Scene loaded additively without unload. Additive scene loading accumulates memory. Loading 5 additive scenes without unloading any is 5x the memory of a single-scene game.

AudioClips loaded in memory. Uncompressed or pre-decompressed audio clips consume memory permanently. A 3-minute music track at 44.1 kHz stereo uncompressed is 30 MB in RAM.

Browser limits. iOS Safari imposes a hard 2 GB WebAssembly heap cap. Desktop browsers cap at 2 GB by default, 4 GB with flag. Embedded browsers (Discord activities, Roblox iframes) may cap lower.

The Fix

Step 1: Enable Memory Growth and set Initial Size. Player Settings > WebGL > Publishing Settings:

Setting Initial too low causes slow start as memory grows. Too high causes failure on low-RAM mobile devices. 256–512 MB initial is the sweet spot for most games.

Step 2: Compress textures aggressively. In texture import settings:

Run the Memory Profiler in Editor, sort by Texture2D, look for your largest textures, and compress them. Reducing peak texture memory by 50% is often achievable with no visible quality loss.

Step 3: Stream audio. Set audio clips to “Streaming” Load Type in import settings. Streaming clips do not live fully in memory; they decode on demand. The tradeoff is slight latency on first play, which is acceptable for music and ambient audio (not for tight SFX).

For short SFX, use “Decompress On Load” which costs RAM but plays instantly. Music and long voiceover: Streaming.

Step 4: Enable IL2CPP code stripping. Player Settings > Other Settings > Managed Stripping Level: High. This removes unused .NET assemblies from the build, reducing both code size and memory footprint. Test thoroughly — High stripping can remove things reflection needs. Add a link.xml to preserve types used via reflection.

<!-- Assets/link.xml -->
<linker>
  <assembly fullname="MyGame" preserve="all"/>
  <assembly fullname="Newtonsoft.Json" preserve="all"/>
</linker>

Add assemblies that use reflection or get stripped aggressively. Run the build and confirm no runtime crashes.

Measuring Actual Memory Use

Enable the Unity Memory Profiler in Player Settings > WebGL > Publishing Settings (or add the “Profiler” package). Connect via WebGL support in the Profiler. Take snapshots to see peak memory, which assets dominate, and where growth happens. Without this data, optimization is guessing.

In the browser, use unityInstance.Module.HEAPU8.byteLength / 1048576 in DevTools console to see current heap size in MB.

Mobile-Specific Strategy

If your game targets mobile WebGL, plan for 1–1.5 GB peak memory maximum. Serve a lightweight version to mobile and a full version to desktop based on user agent:

// In your index.html
if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
    alert("iOS: please use desktop for best experience");
}

Or ship two builds (lite and full) and pick based on device.

“WebAssembly memory is not your computer’s memory. It is a fixed box with a hard edge and a hard failure mode. Budget accordingly.”

Related Issues

For HTML5-specific setup, see Setting Up Crash Reporting for HTML5 Browser Games. For general memory leak patterns, Unity Memory Leak Texture Not Releasing covers related issues.

Memory Growth on, Initial 256 MB, textures crunched, audio streamed. WebGL ships.