Deallocating heap objects when removing mesh from scene

As mentioned from StackOverflow: http://stackoverflow.com/questions/25126352/deallocating-buffergeometry

The good news is, it’s not a bug. The bad news is it’s a change in the system that might catch a lot of people off-guard.

It looks like the old (< r68) way of handling object deallocation is _webglObjects is refreshed with each call to render. When you remove Mesh from the scene and nullify it, the _webglObjects refreshes–sans the Mesh–on the next render. After that, GC can safely remove the Mesh form the heap.

In r69dev, there is no magical refresh of _webglObjects. Removing and nullifying a Mesh leaves a reference to the Mesh in _webglObjects. GC then isn’t be able to remove the Mesh (or even the geometry/material) from the heap, resulting in my “leak.”

The thing I missed between r68 and r69dev is that when you remove a mesh in r69dev, you need to explicitly call dispose on it before nullifying it. Calling dispose triggers removeObject for the Mesh, which updates _webglObjects array. No more references lets GC happily collect the Mesh and associated data.

I’m mentioning it as a concern because bringing r68 code into r69dev was mostly seamless, and this issue wouldn’t have been on my radar if I weren’t dealing with large amounts of geometry. Also, it’s slightly odd not needing to call dispose on Object3D objects that are part of the scene, though I did see the method now exists.

Author: Fantashit

5 thoughts on “Deallocating heap objects when removing mesh from scene

  1. Here’s a start:

    scene.traverse( function ( object ) {
    
    	if ( object.geometry ) geometry.dispose();
    	if ( object.material ) material.dispose();
    
    } );
  2. If it helps, this is the dispose I have for scene BTW -maybe overkill, but seemed to work for my memory tests, you might have better.

    passing the scene to the function :

    function doDispose (obj)
        {
            if (obj !== null)
            {
                for (var i = 0; i < obj.children.length; i++)
                {
                    doDispose(obj.children[i]);
                }
                if (obj.geometry)
                {
                    obj.geometry.dispose();
                    obj.geometry = undefined;
                }
                if (obj.material)
                {
                    if (obj.material.map)
                    {
                        obj.material.map.dispose();
                        obj.material.map = undefined;
                    }
                    obj.material.dispose();
                    obj.material = undefined;
                }
            }
            obj = undefined;
        };

    Also I have this for renderer :

     renderer.dispose();
       renderer.forceContextLoss(); 
       renderer.context=undefined;
       renderer.domElement=undefined;

Comments are closed.