Reputation: 1021
I am using a temporary DOM div container and THREE.js renderer inside my javascript "Image SNAP Function" to produce a high-resolution image file of the current scene which the user can view outside the browser and/or save to disk as a .JPG file.
It all works fine except that another 0.14Gb of memory is used for each "snap" and not released. After a few snaps the PC performance degrades badly. The memory can be released by closing the "app" (browser tab window) but this is very inconvenient for the user.
I have tried various commands to release the memory within the Image Snap function, but they do not do the job.
Here is the code of the Image Snap function:-
function F_SNAP_JPG()
{
var bigContainer = document.createElement('div');
bigContainer.style.cssText = 'id: "bigContainer", width: 4000, height:2200 ';
document.body.appendChild( bigContainer );
bigContainer.innerHTML = "";
var bigRenderer = new THREE.WebGLRenderer( {antialias:true , preserveDrawingBuffer: true} );
bigRenderer.setPixelRatio( window.devicePixelRatio );
bigRenderer.setSize( 4000, 2200 );
bigContainer.appendChild( bigRenderer.domElement );
//--------------------------------------------------------------------------------------------
// RENDER
bigRenderer.render ( scene, camera );
//--------------------------------------------------------------------------------------------
//... make an image of the rendition and allow user to view it outside the browser or save it as a file.
var strMime = "image/jpg";
var fileURL = bigRenderer.domElement.toDataURL( strMime );
//... after & thanks to http://muaz-khan.blogspot.co.uk/2012/10/save-files-on-disk-using-javascript-or.html
var Anchor = document.createElement('a'); //... creates an html <a> anchor object.
document.body.appendChild( Anchor ); //... for Firefox, not needed in Opera (?)
Anchor.style = "display: none";
Anchor.href = fileURL;
Anchor.target = '_blank';
Anchor.download = filename || 'unknown';
Anchor.click();
document.body.removeChild( Anchor ); //... OK.
//--------------------------------------------------------------------------------------------
//...try various ways to release memory
bigContainer.removeChild( bigRenderer.domElement ); //... removes container from screen.
//... with no more instructions beyond here, memory increases 0.14Gb with every snap.
bigRenderer.dispose();//... seems OK
//... but with no more instructions beyond here, memory increases 0.14Gb with every snap.
document.body.removeChild( bigContainer ); //... seems OK
//... but with no more instructions beyond here, memory increases 0.14Gb with every snap.
bigContainer.delete(); //... seems OK
//... but with no more instructions beyond here, memory increases 0.14Gb with every snap.
}//... End of function
What can be done to release the memory (short of closing down the browser tab window)?
Update (Solution)
I found a solution in this answer by Konstantin Eletskiy in this 2015 Stack Overflow post:- Clean up Threejs WebGl contexts.
The solution is to add a single line
bigRenderer.forceContextLoss();
//bigRenderer.context = null; // not needed here.
//bigRenderer.domElement = null; // not needed here.
//bigRenderer = null; // not needed here.
to the end of the F_SNAP_JPEG
function. The other 3 lines were not needed here - possibly becuase I also removed all the DOM
bigContainer
stuff as suggested by George and theJim01. Now there is no detectable memory leakage for at least 9 snapshots.
Upvotes: 1
Views: 1021
Reputation: 8866
I agree with George. Here's a re-write that might help reduce some of that build-up.
A couple things about the code below:
appendChild
), but you really don't need it.
bigContainer
at all.const F_SNAP_JPG = ( function () { // TheJim01: Putting this in an IIFE closure for element re-use
const bigContainer = document.createElement( 'div' );
bigContainer.style.width = '4000px';
bigContainer.style.height = '2200px';
document.body.appendChild( bigContainer );
const bigRenderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );
bigRenderer.setPixelRatio( window.devicePixelRatio );
bigRenderer.setSize( 4000, 2200 );
bigContainer.appendChild( bigRenderer.domElement );
const Anchor = document.createElement( 'a' );
Anchor.style.display = 'none';
Anchor.target = '_blank';
document.body.appendChild( Anchor );
return function () { // TheJim01: This is the actual function that gets called, so place breakpoints in here.
bigRenderer.render( scene, camera );
let fileURL = bigRenderer.domElement.toDataURL( 'image/jpg' );
Anchor.href = fileURL;
Anchor.download = filename || 'unknown'; // TheJim01: filename is always undefined! Mistake? Missing parameter?
Anchor.click();
Anchor.href = ''; // TheJim01: Removing the dataURL string.
};
} )();
Upvotes: 2