I am having many problems to get rid of memory leaks using three.js in a reactive application. Investigating the problem, I found that I am not even able to correctly dispose a scene (without rendering). Let me show you:
https://plnkr.co/edit/Z0sXOnXYc2XOV4t9tETv
In the above example, initially 3 THREE objects are instantiated (as you can see there is no rendering going on, just instantiating the objects):
- scene
- camera
- renderer
Using the chrome devtools let’s take a memory snapshot just after loading the page:
Now let’s click on the “ADD 1000 MESHES” button, which as you can guess simply create 1000 meshes (BoxGeometry + MeshBasicMaterial) and add them to the scene object. Let’s take another memory snapshot and see the comparison (delta) with the previous snapshot:
As you can see we passed from 25.2 Mb to 36.2 Mb and there are +1000 Mesh objects added in memory.
Now clicking the “DISPOSE” button we’ll trigger the following dispose function:
const dispose = (e) => {
// dispose geometries and materials in scene
sceneTraverse(scene, o => {
if (o.geometry) {
o.geometry.dispose()
console.log("dispose geometry ", o.geometry)
}
if (o.material) {
if (o.material.length) {
for (let i = 0; i < o.material.length; ++i) {
o.material[i].dispose()
console.log("dispose material ", o.material[i])
}
}
else {
o.material.dispose()
console.log("dispose material ", o.material)
}
}
})
scene = null
camera = null
renderer && renderer.renderLists.dispose()
renderer = null
addBtn.removeEventListener("click", addMeshes)
disposeBtn.removeEventListener("click", dispose)
console.log("Dispose!")
}
In this function we traverse the scene and dispose every geometry and material. Then we set to null the references to scene, camera and renderer and finally we remove the listeners to avoid memory leaks. Let’s click on DISPOSE button and take another memory snapshot. I expected that the garbage collector will completely remove from memory all the data related to the 1000 Meshes (Mesh, Matrix4, Vector3, BoxGeometry, etc…) but if we take another memory snapshot we’ll find something very different:
It seems that 1000 Mesh objects have been deleted, but the memory usage is almost the same as in the previous snapshot (34.6 vs 36.2 Mb). There are some drops in the Vector3, Matrix4, Quaternion and Euler objects, but most of the objects keep to be persisted in memory and are not collected from the garbage collector. Indeed, if we compare the snapshot 3 to the snapshot 1 we find exactly that:
Please could someone explain what’s going on and how correctly dispose things in three.js?
Three.js: 102 Google Chrome: 72.0.3626.121 (64-bit)