I am running into WebGL memory issues when disposing BabylonJS engines. BabylonJS is only used within one module of my SPA. That module is not necessarily being used when using the app. This is why the BabylonJS engine and therefore all their scenes/meshes/… are disposed when exiting that part of the app. Unfortunately they seem to remain in memory:
Each new BabylonJS engine creates a new WebGL context within the browser. Because the engines are not correctly disposed, the amount of WebGL contexts keeps growing until app crash or browser warning.
so something else is holding on to the created engine do you keep them somewhere in array ?
Normally if you select it, on the bottom panel in Chrome Dev tools, you should be able overriding the retention points, to see where is the code holding onto them
I could not find any reference. I tried reproducing in the playground and found strange behaviour. Please try the following code within the browser console on a random playground (https://www.babylonjs-playground.com):
let canvas = document.createElement('canvas');
canvas.id = 'ourTestCanvas';
canvas.style.position = 'absolute';
canvas.style.border = '5px solid red';
canvas.style.top = 0
canvas.width = 500;
canvas.height = 500;
document.body.appendChild(canvas);
let ourEngine = new BABYLON.Engine(canvas);
let ourScene = new BABYLON.Scene(ourEngine);
let camera = new BABYLON.FreeCamera("ourCamera", new BABYLON.Vector3(0, 5, -10), ourScene);
ourEngine.runRenderLoop(() => ourScene.render());
ourEngine.stopRenderLoop();
canvas.remove();
ourEngine.dispose();
canvas = null; ourScene = null; ourEngine = null; camera = null;
As a result, Safari DevTools still shows ourTestCanvas. Did I do something wrong?
I wasn’t able to repro this on MacOS 11.6 and Safari 15.0 (16612.1.29.41.4, 16612). The testCanvas doesn’t show up for me in the Graphics tab after running your code in the console. What versions are you running?
The root symptoms of my app were naturally independent of the browser dev tools. They occurred in Google Chrome (Version 94.0.4606.81 (Official Build) (x86_64)), Google Chrome Canary (97.0.4666.0 (Official Build) canary (x86_64)), Safari Version 15.0 (16612.1.29.41.4, 16612) and Safari Technology Preview (Release 133 (Safari 15.4, WebKit 16613.1.2.2)).
Interestingly, the engine seems to be correctly disposed when running all the code at once (even on my machine with said browsers). But if I split it into multiple parts (especially separating the running and disposing), it doesn’t work and still shows the second WebGL context after disposing the engine and setting the variables to null. For example:
let canvas = document.createElement('canvas');
canvas.id = 'ourTestCanvas';
canvas.style.position = 'absolute';
canvas.style.border = '5px solid red';
canvas.style.top = 0
canvas.width = 500;
canvas.height = 500;
document.body.appendChild(canvas);
let ourEngine = new BABYLON.Engine(canvas);
let ourScene = new BABYLON.Scene(ourEngine);
let camera = new BABYLON.FreeCamera("ourCamera", new BABYLON.Vector3(0, 5, -10), ourScene);
If you run the code in the answer without the inspector open, you will see the normal number of canvases. But if you have the inspector open when the code runs, it will keep a reference to every single canvas that gets created, resulting in a huge memory usage. I guess it is preventing the canvases from getting garbage collected, for debug purposes.
Can you try running your code to create and dispose an engine without the inspector open, and then check at the end if the canvas was still retained?