Problem with transferable objects in Web Workers

ArrayBuffers (normal and position ArrayBuffers of BufferGeometry object) are not released from the memory when the object is loaded on a web worker and transferred to the main thread.

//main thread
// This is the similiar code that I have

var mesh, renderer, scene, camera, controls;
var models =[];
var loaded_object;
var worker = undefined;
init();
animate();

function init() {

    // renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    // scene
    scene = new THREE.Scene();
    
    // camera
    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.set( 20, 20, 20 );

    // controls
    controls = new THREE.OrbitControls( camera );
    
    // ambient
    scene.add( new THREE.AmbientLight( 0x222222 ) );
    
    // light
    var light = new THREE.DirectionalLight( 0xffffff, 1 );
    light.position.set( 20, 20, 0 );
    scene.add( light );
    
    // axes
    scene.add( new THREE.AxesHelper( 20 ) );

    // geometry
    var geometry = new THREE.SphereGeometry( 5, 12, 8 );
    
    // material
    var material = new THREE.MeshLambertMaterial({
	       color: 0x99C9E9,
		overdraw: 1,
		wireframe: false,
		vertexColors: THREE.FaceColors
});
    
    // mesh
    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );
    
}


function animate() {

    requestAnimationFrame( animate );
    
    //controls.update();

    renderer.render( scene, camera );

}
var worker = undefined;
document.getElementById('upload_model_btn').onclick =function(){
	//...
  worker = new Worker('upload_model.js');
  worker.addEventListener('message',display_model,false)
  worker.postMessage('message',model_filepath);
}


function display_model(event){
	//e.data.normal is the arraybuffer of the loaded object which was tranferred from the worker.
		var main_normal= new Float32Array(new ArrayBuffer(e.data.normal.byteLength));
		main_normal.set(new Float32Array(e.data.normal));

		var main_position = new Float32Array(new ArrayBuffer(e.data.position.byteLength));
		main_position.set(new Float32Array(e.data.position));

		worker_position = null;
		worker_normal = null;

		var bufferGeometry = new THREE.BufferGeometry();
		bufferGeometry.addAttribute('position',new THREE.BufferAttribute(main_position,3));
		bufferGeometry.addAttribute('normal',new THREE.BufferAttribute(main_normal,3));
		loaded_object = new THREE.Mesh(bufferGeometry,material);	

		main_position = null;
		main_normal = null;
		delete e.data.normal;
		delete e.data.position;

		bufferGeometry.dispose();
		bufferGeometry = null;
		scene.add(loaded_object);
   worker.removeEventListener('message',display_model);
    worker.terminate()
    worker = undefined;
    
}


//when I delete the model, I have:
function delete_loaded_object(){
  scene.remove(loaded_object);
  loaded_object.geometry.dispose();
  loaded_object.geometry = null;
  loaded_object.material.dispose();
  loaded_object.material = null
  renderer.renderLists.dispose();
	loaded_object = null;
}





//upload_model.js web worker.
var loader = new THREE.STLLoader();
var transfer_list={}
self.addEventListener('message', function(e) {
            loader.load(e.data.filepath, (bufferGeometry)=>{       
                    transfer_list.normal = bufferGeometry.getAttribute('normal').array.buffer,
                    transfer_list.position =  bufferGeometry.getAttribute('position').array.buffer
                    // bufferGeometry.dispose();
                    // bufferGeometry = null;   
                    self.postMessage(transfer_list,[transfer_list.normal,transfer_list.position]);
                    transfer_list = null;
                });
  }, false);

When I look up the memory after the deletion of the object, the difference before the object was loaded and after it was deleted is exactly the total amount of bytes of position and normal ArrayBuffers that I have.

Moreover, the only way to release this amount of memory is if I explicitly invoke the garbage collector of Chrome browser. I am not sure if there’s something wrong with my code or if there’s a bug on the three.js library because clearly the objects are not being disposed.

Thank you and I do apologize for the formatting and if I was not clear enough describing the problem.

1 Like

Moreover, the only way to release this amount of memory is if I explicitly invoke the garbage collector of Chrome browser.

Calling dispose() and setting a variable to null do not immediately free the related memory. These operations only ensure that references to the objects are removed and a deletion is possible. The actual memory clean up is performed by the GC.

I know that the actual memory clean up is performed by the GC, but it does not happen unless I explicitly invoke it.

“Calling dispose() and setting a variable to null do not immediately free the related memory”
I have waited for long periods of time and the memory resources were never released.

Does this problem only occur with a worker? What happens when you put everything in the main thread?

There’s no memory leak, the occupied computer memory space before and after deletion of the object is the same.

It would be useful to know if the memory is also not release when your entire code is executed in the main thread. That was my question about.

OK, maybe I was no clear enough. If I don’t use the web worker, which means that I am runnning my entire code in the main thread, than there are NO memory leaks.

Okay, I see. Any chances you provide a live demo that demonstrates the problem?

JSFiddle is giving me hard time with http requests as I can’t find a server where I can put the files.

Sry, your fiddle does not work for me. I’m getting the following error when loading the STL.

three.min.js:652 Mixed Content: The page at ‘blob:https://fiddle.jshell.net/31ed3519-7feb-4d36-b75a-566471fc2774’ was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint ‘http://formon3d.com/update-fb/files/t8nut50.stl’. This request has been blocked; the content must be served over HTTPS.

Yeah, i am not sure if i will be able to do a live demo in the upcoming days. But i will keep u posted. In the meantime let me know if by any chance you find the cause of the problem.