I already figured out quite some things about the weird workings of WebGL and how to build projects, so they work on as many machines and devices as possible.
However, I am still facing a few issues, especially with Apple devices like iPhones.
Some key questions I have are the following:
What is the reason that the page is refreshing occasionally? I try to keep my games at 200-300mb when running, but for some reason some keep refreshing and some don’t
I have a webpage that contains an IFrame that loads the game. But within the game I want to switch to another minigame (another unity project), but when I do that (using the react-unity-webgl plugin from jeffrey lantern), it does not free up the memory even though I use the “unload()” method. Therefore, the memory keeps piling up and results in a crash
What are the best settings for building when having the goal of supporting all kinds of devices (desktops, laptops, android, ios), I am currently building 2 version of the game, one for desktops that use the DXT format and one for mobile that use ASTC format (build settings are shown below).
BTW: I am using Unity 2022.3.0 on Apple silicon with M2 processor.
My player settings are the following:
Other settings:
Basically, Apple has a watchdog feature in Safari, that it will reload web pages when they reach a certain undocumented threshold of memory usage. We don’t know how that threshold is calculated, or whether it is static, or dependent on other factors (like # of tabs open, or # of total apps open, or # of RAM on the device), but we have observed that WebGL content on Safari would be good to keep between 300MB-500MB of RAM consumption max to work best.
We have asked Safari to consider the design of this feature, and they have heard the feedback, although they do not comment on future design features of their browser (so we don’t know how Safari will work in the future).
Proper unloading of iframes is a bit delicate to do right, due to JavaScript event handlers and retaining scopes. If memory is not fully freed by garbage collector, it most likely means that there was some JavaScript dependency that prevented the unload from occurring.
To remedy this, try to familiarize yourself with the Memory tab snapshotting in web browser DevTools, and how to diagnose retainer trees. That should show what is keeping the page in memory.
Also, be sure to update to latest point release of Unity. I recall I have fixed an issue around this in the past year or so, so if your Unity version is a bit out of date, it might not have had the fix yet.
In latest Editor versions, if you do a Development build using the default page template, you will see a Unload button generated on the web page. That allows you to double check how to implement the unloading behavior so that it will properly unload everything.
Currently doing dual builds is the recommended way, but the team is looking into improving this workflow, either by implementing support for Basis compressed textures (that would work against each compressed texture format), or by adding support for multiple compressed format builds.
I was tinkering around with my project and actually got it down to about 200MB of Memory Usage when playing.
This was measured using chrome on a MacBook Pro.
I also got the unloading to work, so there should be no “old memory” from previous games. I also just started a single game without any game loading prior / having anything in cache.
But still my game crashed after about 5–10 seconds when the loading is done.
I measured the memory on chrome after that time, but there was no change in memory. I am also not doing anything in the game nor is it loading any external data or similar.
Maybe you have some more advice how to pin this issue down. I am currently out of ideas
PS:I also upgraded my editor version to the latest 2023 release.
There is a memory leak in textcore on Unity 2022.3.x and below. This was crashing my WebGl game on Safari pretty fast. It was fixed in 2022.3.10f1 I believe.
I don’t think that should be an issue, as I am currently building with 2023.1.15f1.
Update 1:
Recoded quite a lot of stuff, might have been an issue on my side. I’ll update this post if I find anything that might help other people.
I also set the initial memory to “only” 128mb, even though the documentation says it should be set to the maximum the game uses up front, I find this solution to be more stable.
You can set an Emscripten linker argument “–memoryprofiler” to generate a very low-level memory profiler from Emscripten onto the page. Close Editor, edit ProjectSettings/ProjectSettings.asset, find webGLEmscriptenArgs: and change it to
webGLEmscriptenArgs: --memoryprofiler
The profiler is not implemented by Unity, but comes directly from the Emscripten project. To make it work, use a Development build, or a Release build with Debug Symbols set to Embedded.
That might give a hint towards if there is something in the WebAssembly Memory area that is leaking.
I redeployed my solution with the emscriptenargs, I am getting the following console logs in Javascript:
memory resize: 134217728 150994944
memory resize: 150994944 167772160
memory resize: 167772160 184549376
After that, it keeps playing for around 5 seconds and then crashes.
If I am not mistaken, that is only around 185mb, right?
Update: Here is a link to check it out yourself (will remove soon, also built without the memory profiler)
— Link removed —
(Just wait a bit and it will crash)
That print does mean that the WebAssembly content is ~185MBytes, but the total amount used by the web page is more, since it contains (among other things) the compiled Wasm Module, the JS scope, audio, and all GPU memory. Those are outside the WebAssembly Memory.
The idea I was thinking with using --memoryprofiler is to run the page on e.g. desktop Chrome where the Safari crash will not occur. And then see if the WebAssembly Memory size grows unboundedly up to gigabytes of size as you let time pass. If that happens, then it suggests a memory leak somewhere, that might be the root cause that is giving Safari a hard time. If such runaway memory usage doesn’t happen, then the issue might be just that the page uses too much for Safari to like.
Also, Firefox has a nice “about:memory” special URL address that opens a memory profiler. That one is nice as well to use for profiling memory usage.
You can also try using Safari’s DevTools to check what the total memory usage is outside the WebAssembly Memory for a total picture.
I see the link was removed, so I was not able to check the site.
However, I actually found out the problem is something different (read below).
To everyone that might also have this kind of issue:
I was able to get a stable version for Safari + iPhone by:
using the settings above
setting the initial memory size to 128mb (as my game usually only goes up to around 200-250mb)
set all textures that are downloaded via the UnityWebRequest Handler to Non-readable
Limit the texture sizes to 512x512 with normal + crunch compression
Create Dual builds (with DXT Compression for Desktop and ASTC for mobile)
and MOST IMPORTANTLY in my case: disable GPU instancing for materials
Regarding the GPU instancing:
If you have large meshes with more than 256 Vertices, you can enable GPU instancing for your materials, and it will actually give you quite a nice increase in performance.
However, if you have multiple meshes with less than 256 Vertices, the GPU instancing option heavily impacts game stability. I had as little as 5–10 Meshes that are below that threshold, and it would lead to a crash on iPhone + safari. Once I disabled the GPU instancing option, my game runs stable and smooth with a mixture of large meshes (>256 Vertices) and small meshes (<256 Vertices). More information about GPU instancing can be found here: Unity - Manual: GPU instancing
I will update this Post if I happen to find more information on what can lead to a page refresh on safari+iPhone.
UPDATE 10/10/2023:
Looks like the Solution I found is semi-perfect. It works without page refreshing on Apple devices like the iPhone 12 and newer. Older devices occasionally refresh without any log, notice, memory increasing, etc.
I will add two tips that helped me when developing for multiple web devices.
Browser Stack is a pretty nice website that lets you test your app on many different real devices.
WebGL and iOS do not play nicely. I had to downgrade our project to Unity 2020.3 LTS with built in render pipeline. I don’t know why that was the most stable we tested, but it was.
Yes I also think Browserstack is a useful tool for debugging, especially on various kinds of iPhones.
You might want to look into the automate tool they are offering,
I wrote a simple script that would start the game on different devices automatically and check if the game was still running after a few minutes, this allowed me to iterate faster than doing the testing manually.