17

What is the proper way to remove mesh form scene? In this example:

    removable_items = [];
    box = new THREE.Object3D();
    scene.add(box);

    function add() {
        var mesh = new THREE.Mesh( new THREE.IcosahedronGeometry( 10, 5 ), new THREE.MeshPhongMaterial( {color: 0xFFFFFF}) );   
        box.add( mesh );
        removable_items.push(mesh);
        //clean(); ///// when is integrated in function memory is cleaned properly
    }   

    function clean() {
          if( removable_items.length > 0 ) {
            removable_items.forEach(function(v,i) {
               v.parent.remove(v);
            });
            removable_items = null;
            removable_items = [];
          }
    }

    function makeExperiment(r) {
      var i = 0;
      while (i < r) {
        add();
        i++;
        if( r === i ) console.log(r+' finnished ');
      }
    }

makeExperiment(50);

/// after that i mannualy set clean();

meshes are not visible at scene anymore, as expected, but sill using memory, which after some time finish with memory leak and browser crash.

Where is the problem, did THREE.js making some other references?

THREE.js R73

EDIT: when is clean(); integrated in function (commented now in code) memory is cleaned properly. But when I set clean(); manually after makeExperiment(); is done, memory is not set as free.

Martin
  • 2,575
  • 6
  • 32
  • 53
  • I'm looking at this -- what program/tool do you use to look at memory? – dcromley Jun 12 '16 at 19:37
  • Your statement `new THREE.IcosahedronGeometry( 1, 5 )` The 2nd parameter is detail. Having it as 5 makes for a lot of processing. Is that part of your problem that you want answered? The default is 1. – dcromley Jun 13 '16 at 01:39
  • Im using high detail mesh by reason, to clearly illustrate the memory example. It is the same problem with the JSON or OBJ models, or box geometry, only need to repeat makeExperiment function longer. Im using chrome console and chrome memory snapshot. – Martin Jun 13 '16 at 06:25
  • are you sure `v.parent.remove(v);` will work as expected? – 2pha Jun 17 '16 at 10:04
  • yap, no difference when i Set box.remove(v) – Martin Jun 17 '16 at 11:48

1 Answers1

20

I've done a few experiments and i think there is nothing really wrong with your code. One thing that i've learned though, is that that garbage collector might not run exactly when you think it does. Just in case, I wrapped your code in a IIFE (good practice but not necessary in this case) and expected the heap to be cleared as soon as the function finished running and went out of scope. But it actually took some time for it to clear:

clean 50

So i thought, okey, thats not to good, what if i was creating more objects in that timespan where the garbage collector is just lingering, so i did:

.
.
makeExperiment(50);
clean();
makeExperiment(50);
clean();
makeExperiment(50);
clean();
makeExperiment(50);
clean();
makeExperiment(50);
clean();
makeExperiment(50);
clean();
makeExperiment(50);
clean();
makeExperiment(50);
clean();

and this is what happened:

clean 400

The garbage collector seems to be doing its job, and you are deleting them correctly for this purpose. However, You are probably using THREE.js Renderer aswell, and if I understand it correctly, the Renderer keeps references to materials, geometries and textures. So if these are not disposed of correctly, they will not be garbage collected. THREE.js has a method for Geometrys, Materials and Textures called .dispose() which will notify the Renderer to remove it aswell. So this is how I would change your clean() function:

removable_items.forEach(function(v,i) {
  v.material.dispose();
  v.geometry.dispose();
  box.remove(v);
});
micnil
  • 4,705
  • 2
  • 28
  • 39
  • hi and thx! as i see in your graph, the removing still leave data in heap, when i do this experiment thousands time, it will cause browser unresponsive. I'm using this situation in game, and there is a huge need of reloading new objects (enemies) and remove old-ones - deaths. Did you try it with integrated clean() function inside add() function? (commented line in my code) or did you run clean() manually after some time delay? – Martin Jun 21 '16 at 09:54
  • 1
    @Martin I tried to clean inside the `add()` function and manually after the `makeExperiment()` (as seen above). You cannot control exactly when the browsers garbage collector will decide to clean, if you want some variable cleared, all you can do is remove all references of it. When calling `clean()` inside `add()` the garbage collector still did not clean the heap 50 times, only about 6 times, so it was the same behaviour. The reason browser is unresponsive is because javascript is single threaded, and you are using that thread to do something 1000 times. try dividing it up on multiple frames – micnil Jun 22 '16 at 01:46