In my BabylonJS project, I used the queryObjects(Promise) command and found that several thousand Promise objects were leaking memory.As shown in the figure below.
I tried to analyze the memory leak Promise objects. I guessed it was GLTF loading module, so I tried to modify the source code of the module, and it worked.The culprit from GLTFFileLoader. prototype. loadAssetContainerAsync, here is my modified code.
GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
this.onParsedObservable.notifyObservers(data);
this.onParsedObservable.clear();
this._log(`Loading ${fileName || ""}`);
this._loader = this._getLoader(data);
// Prepare the asset container.
const container = new AssetContainer(scene);
// Get materials/textures when loading to add to container
const materials = [];
this.onMaterialLoadedObservable.add((material) => {
materials.push(material);
material.onDisposeObservable.addOnce(() => {
let index = container.materials.indexOf(material);
if (index > -1) {
container.materials.splice(index, 1);
}
index = materials.indexOf(material);
if (index > -1) {
materials.splice(index, 1);
}
});
});
const textures = [];
this.onTextureLoadedObservable.add((texture) => {
textures.push(texture);
texture.onDisposeObservable.addOnce(() => {
let index = container.textures.indexOf(texture);
if (index > -1) {
container.textures.splice(index, 1);
}
index = textures.indexOf(texture);
if (index > -1) {
textures.splice(index, 1);
}
});
});
const cameras = [];
this.onCameraLoadedObservable.add((camera) => {
cameras.push(camera);
});
return this._loader.importMeshAsync(null, scene, true, data, rootUrl, onProgress, fileName).then((result) => {
Array.prototype.push.apply(container.geometries, result.geometries);
Array.prototype.push.apply(container.meshes, result.meshes);
Array.prototype.push.apply(container.particleSystems, result.particleSystems);
Array.prototype.push.apply(container.skeletons, result.skeletons);
Array.prototype.push.apply(container.animationGroups, result.animationGroups);
Array.prototype.push.apply(container.materials, materials);
Array.prototype.push.apply(container.textures, textures);
Array.prototype.push.apply(container.lights, result.lights);
Array.prototype.push.apply(container.transformNodes, result.transformNodes);
Array.prototype.push.apply(container.cameras, cameras);
return container;
});
};
The following is a comparison of the revised data.You can see that memory has fallen by a few hundred megabytes, and there are a few thousand fewer Promise objects that are leaking memory.But there are still hundreds of Promise objects that have memory leaks.
I opened the playground project, and an empty project also had dozens of Promise objects leaking memory.As shown in the figure below.
I’m sure there are several Promise memory leaks in the BabylonJS source code, and I can’t fix them all. It’s up to you to fix them yourself.
I have two suggestions: 1. Remove the nested Promise and chain calls and use async/await instead to make the code more elegant.2. Remove unnecessary asynchronous code.I found it pointless to execute synchronous code in Promises, which could potentially cause memory leaks, and I found a lot of such code in the source code.