What is the best way to effectively clear memory in THREE.js?

After successfully rendering the model, rotating and zooming work perfectly. However, when attempting to clear the scene by clicking the button#clear, issues arise.

The expectation is to traverse through the scene, add its children to an array, iterate over the array, clear each item by calling dispose() on geometries or materials, and then remove the meshes from the scene.

<html>
  <head>
    <title>Three.js</title>
    <link rel="stylesheet" href="css/main.css" />
  </head>
  <body>
    <button id="clear">Clear Three Out</button>
    <script src="js/three.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="js/ObjectLoader.js"></script>
    <script>
    ...
      (function(){var script=document.createElement('script');script.onload=function(){var stats=new Stats();document.body.appendChild(stats.dom);requestAnimationFrame(function loop(){stats.update();requestAnimationFrame(loop)});};...   };

        ...   scene.add( object );
        ...     }
      );

      scene.translateY(-345);

      var holder = [];

      
      document.getElementById('clear').onclick = function() {
        
        console.log('holder before clean: ', holder);
        for (var i = 0; i < holder.length; i++) {       }

          scene.remove(holder[i]);
        }
        console.log('holder after clean: ', holder);
      }

      
      
      ...

      bowLoop();
    </script>
  </body>
</html>

Console logs:

Children of the scene

...

Holder array before cleaning:

...

Holder array after cleaning:

...

No memory change as objects remain in heap.

Answer №1

Upon reflection, two key points emerge:

  • The issue likely arises from holder retaining references to objects even after the clear-function has been invoked (credit to @pailhead). Consider adding holder = []; at the conclusion of the function to eliminate these references. It is also important to ensure that no other accessible variables are holding onto object references.

  • Keep in mind that the objects will not immediately be removed from memory; they will only be collected by the garbage collector once it completes its task. Depending on various factors, this process may take some time.

Answer №2

@gaitat - I appreciate the extensive solution you provided.

I made a few adjustments to tailor it to my requirements:

  function disposeNode(node) {
    if (node instanceof THREE.Mesh) {
      if (node.geometry) {
        node.geometry.dispose();
        node.geometry = undefined; // issue resolved
      }

      if (node.material) {
        if (node.material instanceof THREE.MeshFaceMaterial || node.material instanceof THREE.MultiMaterial) {
          node.material.materials.forEach( function(mtrl, idx) {
            if (mtrl.map) mtrl.map.dispose();
            if (mtrl.lightMap) mtrl.lightMap.dispose();
            if (mtrl.bumpMap) mtrl.bumpMap.dispose();
            if (mtrl.normalMap) mtrl.normalMap.dispose();
            if (mtrl.specularMap) mtrl.specularMap.dispose();
            if (mtrl.envMap) mtrl.envMap.dispose();

            mtrl.dispose();
            mrtl = undefined; // issue resolved
          } );
        }
        else {
          if (node.material.map) node.material.map.dispose();
          if (node.material.lightMap) node.material.lightMap.dispose();
          if (node.material.bumpMap) node.material.bumpMap.dispose();
          if (node.material.normalMap) node.material.normalMap.dispose();
          if (node.material.specularMap) node.material.specularMap.dispose();
          if (node.material.envMap) node.material.envMap.dispose();

          node.material.dispose();
          node.material = undefined; // issue resolved
        }
      }
    }
    console.log('node before removal: ', node);
    scene.remove( node );
    renderer.dispose(); // ***EDIT*** improved memory usage compared to original scene heap size of 12.4 MB; after adding objects it increased to 116 MB or 250 MB (for different models), but clearing always brought it down to 13.3 MB ... there might still be some artifacts remaining.
    node = undefined; // no longer necessary
  }

  function disposeHierchy(node, callback) {
    for (var i = node.children.length - 1; i >= 0; i--) {
      var child = node.children[i];

      disposeHierchy(child, callback);
      callback(child);
    }
  }

Usage:

document.getElementById('clear').onclick = function() {
    disposeHierchy(scene, disposeNode);
    console.log('renderer.info.memory after: ', renderer.info);
  }

Answer №3

To optimize performance and manage memory efficiently, take a look at the code snippet below for loading GLTF files and releasing memory:

let ZomModel = undefined;
function loadZoom() {
    const gltfLoader = new GLTFLoader();
    gltfLoader.load(modelName, (gltf) => {
        const root = gltf.scene;
        setmaterial(root);
        ZomModel = root;
        root.position.set(0, -3, 0);
        root.scale.set(5, 5, 5);
        scene.add(root);
        console.log(root, 'root')
    });
}
function loadNew(isLoad) {
    console.log("reload " + isLoad);
    // return;
    if (isLoad) {
        if (ZomModel == undefined)
            loadZoom();
    } else {
        // defultmaterial(ZomModel);
        if (ZomModel == undefined) return;
        ZomModel.traverse(object => {
            if (!object.isMesh) return
            scene.remove(object);
            console.log('dispose geometry!')
            object.geometry.dispose()
            if (object.material.isMaterial) {
                cleanMaterial(object.material)
            } else {
                // an array of materials
                for (const material of object.material) cleanMaterial(material)
            }
            object.geometry = undefined;
            object = undefined;
        });
        scene.remove(ZomModel);
        ZomModel = undefined;
    }
}

const cleanMaterial = material => {
    console.log('dispose material!')
    // dispose textures
    for (const key of Object.keys(material)) {
        const value = material[key]
        if (value && typeof value === 'object' && 'minFilter' in value) {
            console.log('dispose texture! ' + key)
            value.dispose();
        }
    }
    material.dispose();
    material = undefined;

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Transferring information from a Jade file to a Node.js server

I'm currently working on creating a data object within my Jade view page that will be used in my server-side JS. The data object involves dynamic HTML generation that inserts input boxes based on user input. function addDetail() { var det ...

Finding and removing an element using Jquery

$.ajax({ type: "GET", url: "ajax/getLinks.php?url=" + thisArticleUrl }).done(function (data) { var extractedContent = $(data).find("#content > div > div.entry.clearfix"); extractedContent.find("#content > di ...

Show only half of the Google Charts

I have a code snippet that displays a chart with dimensions of 500x500. However, I only want to show half of the chart, like 500x250. But whenever I adjust the values in the div, it resizes the entire chart instead of just showing half. My goal is to hide ...

What is the process of importing a JSON file in JavaScript?

Is there a way to import a JSON file into my HTML form by calling $(document).ready(function (){});? The properties defined in the JSON file are crucial for the functionality of my form. Can anyone guide me on how to achieve this? ...

Is there a way to automatically close the Foundation topbar menu when a link is selected?

On my single page website, I am utilizing Zurb Foundation's fixed topbar which includes anchor links to different sections of the page. My goal is to have the mobile menu close automatically whenever a link inside it is clicked. As it stands now, whe ...

The "angular2-image-upload" npm package encountering a CORS issue

Using the angular2-image-upload library for uploading files has been a smooth process until recently. After upgrading from version 0.6.6 to 1.0.0-rc.1 to access new features in future, I encountered issues with image uploads. The errors I faced were: htt ...

The React functional component captures a snapshot of its state when initializing a websocket event handler

When using a react functional component, it captures a snapshot of the state at the time of subscription. For example, refer to the code below. If I click the setSocketHandler button and then press the setWelcomeString button. If I receive a message over ...

Node.js refuses to launch - the dreaded error 404, signaling that it has mysteriously vanished

I am brand new to node.js, so please be patient with me as I learn. Currently, I am using the express framework and attempting to create a basic application that displays content as HTML. Below is the essentials of my app.js: var express = require(' ...

Utilizing an Ajax call within "for" loops can result in skipping either odd or even iterations

Seeking assistance because we are facing a challenge that we cannot seem to overcome. Despite researching on platforms like StackOverflow and search engines, implementing a solution or solving the problem remains elusive. The goal is to develop a JavaScri ...

Leveraging JavaScript to access the margin-top property of the HTML and body tags

I'm having trouble retrieving the "marginTop" style property from the <html> and <body> tags. While Chrome developer tools shows that margin-top is being set via in-HTML CSS: <style type="text/css" media="screen"> html { margin-top: ...

Adding jQuery SVG Sources to SVG Elements

Can the jQuery SVG source code be included in a standalone SVG document? Here is an example: <script type="application/javascript"> <![CDATA[ // jQuery SVG code ]]> </script> I want the SVG document to be self-contained, ...

When utilizing jQuery and Ajax for form submission, PHP is unable to retrieve any data

I'm encountering an issue when trying to submit a form with only a radiobutton group named radiob. The script I am using for submitting the data is as follows: <script type="text/javascript"> $(function() { $("#myForm").submit(funct ...

Issue with ng-grid in AngularJS: Data does not appear after resizing columns

Currently, I am encountering a problem where ng-grid data is not being displayed when column resizing occurs after changing the column names. To demonstrate this issue, I have created a plunkr at - http://plnkr.co/edit/eV9baoDOV9A46FZmKW8G?p=preview I wo ...

Here is a way to retrieve the name of a ref object stored in an array using Vue.js 3 and Typescript

I have a Form, with various fields that I want to get the value of using v-model and assign them to ref objects. In order to populate my FormData object with this data, I require both the name and the value of the ref objects. Unfortunately, I am struggli ...

Modify the file format depending on the browser being used as Internet Explorer

Currently seeking the most effective method to dynamically alter the file extension of certain images (from .svg to .png) specifically for Internet Explorer users. Uncertain about the optimal approach: consider parsing the HTML code with PHP utilize jQu ...

What is the best way to specify a function parameter as a Function type in TypeScript?

I'm currently delving into the world of TypeScript and I am unsure about how to specify a function parameter as a function type. For instance, in this piece of code, I am passing a setState function through props to a child component. const SelectCity ...

The delete function is not functioning

I need help with implementing a custom Angular directive that includes a delete button to remove itself. When I click the button removeMe, it is not deleting an item from the array. Any suggestions on what might be causing this issue? HTML: <button t ...

Struggle with encoding dropdown menu options

I have multiple forms on my webpage and I want to be able to access them all at once and include them in a single large GET request. It's mostly working, but I'm encountering difficulties when dealing with drop down menus because their structure ...

Leveraging React Hooks for managing the Data Provider and Data Context functionality

Currently, I am revamping my DataProvider by upgrading it from a class component to a functional component utilizing React Hooks. I suspect that the issue lies in how I am setting up my context consumer, but I am struggling to find an effective way to tes ...

Is it possible to incorporate an element using absolute positioning using jQuery or Javascript?

When trying to add a new element on the screen, I am facing an issue with the absolute positioning not working properly. Sample Code in Javascript function drawElement(e,name){ $("#canvas").append("<div id='" + name + "' class='e ...