So after some testing with the mobile version of our WebGL application, I found some issue with automatically increasing WebGL memory on iOS.
Whenever the memory needs to increase from 256MB to anything higher, to lets say, 300 to 500MB, the browser tab crashes and does a force reload. The interesting thing is, when publishing the app with a 512MB base memory instead of 256MB, the app loads fine, takes longer to crash as it does not need to increase the memory as quickly.
This happens on all iOS devices I have tested on.
The problem here is that some other mobile (android) devices cannot reserve 512MB at start and will crash without loading. So at this point in time, its a choice between a quick crash on iOS or a application that doesn’t work on other mobile devices.
Another problem with these memory crashes on iOS, is that the browser does an instant page reload without giving an error message. This makes us unable to inform to the user that an error occurred and leaves the user guessing on what happened.
Are these known issues and is there a workaround or fix possible?
When you have a memory budget of 256 MB and the app you run exceeds that, consider this the same issue as running out of free device memory if you were making a native app. You‘re strictly required to ensure the app runs within that memory budget, be it device memory or browser tab memory.
What you need to do is to determine why memory usage spikes too high for a short time (GC alloc, resource load) or continuously increases (not unloading resources, memory leaks).
As for workaround, you can also set 384 MB or any number. However that will just alter how long the app will run before it eventually crashes. If I understood you correctly, it even crashes with 512 mb memory budget. So there‘s your problem, not the budget itself.
I think you misunderstood the issue. iOS can handle 512MB memory fine, but only if it is set as startup memory. If the startup memory is set to 256, it is not able to increase to anything higher, not 512, not 384. This makes me believe that there is an issue with increasing the wasm working memory size on iOS.
When 512MB is used as the startup memory, our application doesnt work on some android devices.
Maybe a temporary solution is to set the startup memory depending on the platform. Is it possible to change the startup memory from the Unity JavaScript WebGL Loader, or would that require seperate builds?
It was my understanding that the startup memory is a hard limit but it is not. However, growing the memory is something that can fail at any time (due to the requirement of “contiguous” allocation). That is why we considered it to be an upper limit because expecting the browser to give you the extra memory you need right now is simply too risky.
So if it works with 512 mb startup but not 256 startup why don’t you try some in-between values like 384 mb? There’s no requirement for startup memory to be on the power of two scale.
Yes, everything is set up correctly and we manage our memory well. The problem is that the automatic memory increase does not work correctly on iOS.
iOS can run 512MB fine, but is not able to use 512MB memory unless it launches with 512MB on startup. When launched with lower amounts of memory, it wont increase past 256MB.
The other issue is that safari will not log any error or crash message and force reloads the page instantly.
Hi!
First of all, how can you change the base memory? I spent the morning trying to do that (Unity 2021.3) and I can’t find it.
I remember old times when it was in the .json file. To do something like you want to, I had two JSON and I decided which one to load based on device. Now I thought it should be in the config object in javascript, so it should be even easier. Did you try that?
Isn’t it detailed in the Unity manual? It used to be in there. Check Player settings (on the WebGL tab obviously), most likely it’ll be in there.
Probably not because the whole memory allocation and in particular incremental allocations in WebGL is a black box and it can fail at any time on any device for seemingly no good reason. Sometimes it’s as easy as restarting a device that constantly runs out of memory, and then it suddenly works fine.
But really the best solution in my opinion is to aggressively lower memory usage all over the board for WebGL apps and allocate the most memory you will need and can safely allocate up front (said “base memory” but I believe the term is different) to minimize or entirely avoid incremental allocations.
Also, do not rely on specifications that say “Browser X can allocate Y memory per tab” because even that is just a theoretical thing. Like an iOS device that has 4 GB of memory, it won’t be able to give all that memory to a single app. Nor does the OS consume a constant amount of memory, and depending on apps installed and device model background processes can also consume a variable amount of memory.
But at least with native apps you have a way to react to memory pressure through OS events. WebGL doesn’t give you that option, hence the recommendation to aggressively lower memory usage.
I have profiled my game and let it run for several minutes and the game never needed to extend memory usage beyond the initial 120MB that it started with. My game is pretty light-weight but for some reason on iOS running on a browser it just randomly lags and crashes.
One thing to note, within an iOS native app running on a webview, it’s running perfectly fine. There’s some memory shenanigans going on, likely on iOS 16 and up that’s causing weird issues on a browser.
Apple has a history of not giving a f*** about anything WebGL related. Certain developments in the web space are threatening their business model. I know this isn’t helpful, just to set expectations.
Anyway, make sure you reboot the test device. If possible, reset it to firmware defaults. If the issue still persists only on that device (or other iOS devices but no Android) then it’s likely an iOS issue.
There are multiple factors that can cause an app to terminate due to memory overage, and I have investigated the following items in the past. If any of them are exceeded, the Unity app will terminate.
Hardware RAM capacity limit
Limits set by Unity build settings
Limit set by browser management (512MB for devices with iOS 4GB RAM, older devices may not even start with 100MB)
*The memory value is based on the memory managed by the browser, not the memory value displayed in the Unity memory profiler, so you should refer to the browser’s debugging function or the memory API by JS.
After many days of struggling with memory issues in WebGL, I finally managed to solve it. Memory is now fully released each time I load a different scene or a page that’s not Unity. So, the solution is that you need to write a JavaScript function to release the objects you no longer use within the UnityInstance, or release the entire UnityInstance if you load a different page.
Here’s a recursive JavaScript function to do this.
function setPropertiesToNull(obj) {
let queue = [obj];
while (queue.length > 0) {
let currentObj = queue.shift();
for (let key in currentObj) {
if (Object.prototype.hasOwnProperty.call(currentObj, key)) {
// Nếu thuộc tính là một đối tượng khác, thêm nó vào hàng đợi
if (
typeof currentObj[key] === "object" &&
currentObj[key] !== null
) {
// Kiểm tra nếu thuộc tính là đối tượng OpenCV (như cv.Mat)
if (currentObj[key].delete) {
// Giải phóng tài nguyên OpenCV
currentObj[key].delete();
} else if (ArrayBuffer.isView(currentObj[key])) {
currentObj[key].buffer = null;
currentObj[key] = null;
} else {
// Thêm vào hàng đợi để tiếp tục xử lý
queue.push(currentObj[key]);
}
}
// Đặt thuộc tính về null, trừ khi đó là một ArrayBuffer view (như Int8Array)
if (!ArrayBuffer.isView(currentObj[key])) {
currentObj[key] = null;
}
}
}
}
}
Hi vulamavi2, thanks for your solution, I am also facing this issue. Our app has similar situation mentioned above.
Especially on iPad browser.
So far increasing publishing setting doesn’t work for my project. We monitor the memory , it goes til around 80~100MB and browser (Safari) reloads.
Once this reload happens, the next launch goes worse. A single texture usage may cause page reload again. Reboot / clear history data doesn’t help a lot.
I tried your solution but it seems that your some objects are not compatible with mine. Page stuck in
setPropertiesToNull() as launching , and doesn’t continue to load unity. Would you mind mentioning how you integrate your 2 functions into index.html?
It’s unlikely that anything noteworthy has changed between 6000.0.22f1 (last Preview) to 6000.0.23f1 (first LTS). There have been bigger changes between 6 and 2023/2022 for sure.
But any differences in performance are going to be highly project-specific. So if you want to know, try it yourself.