Clear memory for loaded models?

When I use the load glb model function, I delete the gameobject I previously loaded but the memory for the webpage doesn’t drop back down (tested in a webview on windows). Is there any way to clear the memory for that loaded glb after destroying the gameobject?

When you load a GLB model and then delete the corresponding GameObject in Needle Engine (or generally in a web context using Three.js or similar engines), you need to ensure that you’re cleaning up all resources associated with that model to effectively release memory.

Here’s a step-by-step approach to ensure you are doing this correctly:

  1. Remove Event Listeners: If you’ve attached any event listeners to the object or its components, make sure to remove them.

  2. Dispose of Three.js Objects:

    • If you’re directly using Three.js objects (like Mesh, Geometry, Material, or Texture), ensure that you call their dispose method. This will help in freeing up GPU resources.
    if (mesh.geometry) {
        mesh.geometry.dispose();
    }
    if (mesh.material) {
        if (Array.isArray(mesh.material)) {
            mesh.material.forEach(material => material.dispose());
        } else {
            mesh.material.dispose();
        }
    }
    
  3. Textures and Materials:

    • Ensure all textures and materials are freed. If your GLB model has textures, dispose of them.
  4. Cleanup Scene References:

    • Make sure that there are no lingering references in your scene graph that might be preventing the garbage collector from reclaiming memory.
  5. Use Performance and Memory Tools:

    • Use browser developer tools to monitor memory usage and ensure that objects are being collected after you perform cleanup.

In Needle Engine specifically, ensure you follow these steps from a component script where you have control over cleanup operations after you destroy the GameObject.

If you’re experiencing specific issues, having the version of Needle Engine and optionally any specific errors or logs would help narrow down the solution. Feel free to provide that for more detailed assistance.

You can find more information on dealing with Three.js resources disposal here in their documentation.

24 replies left
thread_cVcOg00uf8pG3tXLmgbvNEOf
Reply to this message to continue the conversation

Are there any Needle Engine side memory cleanup callbacks to call when I spawn a gameobject using Needle Engine?

Hi Rob_F,

Yes, Needle Engine provides mechanisms to handle cleanup when you spawn GameObjects. Typically, when you want to ensure proper memory management and cleanup, you should implement the following:

  1. OnDestroy Callback:

    • You can implement an OnDestroy method in your component. This method is called when the GameObject is destroyed, giving you an opportunity to perform any necessary cleanup operations, such as removing event listeners or disposing of resources.
    import { GameObjectBehaviour } from "@needle-tools/engine";
    
    class YourComponent extends GameObjectBehaviour {
        onDestroy() {
            // Cleanup logic here
            // E.g., dispose resources or remove any references
        }
    }
    
  2. Dispose Method:

    • If your component manages any resources (like textures or geometries), ensure you have a Dispose method and call it in OnDestroy to clean up those resources properly.
  3. Handling Memory Usage:

    • Monitor the memory usage as you add or remove GameObjects. Use the browser’s developer tools to track memory to ensure that you’re actually freeing up resources.
  4. Garbage Collection:

    • Javascript’s garbage collector will automatically reclaim memory for objects that are no longer referenced, so ensuring that you have removed all references to the GameObject and its components will help with cleanup.

Make sure to always call any cleanup functions in your component’s OnDestroy method to ensure resources are properly released when the GameObject is destroyed.

If you have any specific use cases or situations, feel free to provide more details for tailored advice!

24 replies left
thread_cVcOg00uf8pG3tXLmgbvNEOf
Reply to this message to continue the conversation

I am confused why Gameobject.Destroy doesn’t clear the memory added from loading an object using LoadSync, is there anything obvious I missed here? The mesh doesn’t have geometry it has geometry___needle instead etc, I though that would be cleaned up by Needle when the object is detroyed. If I keep loading an object with Loadsync then destroying it after the memory grows exponentially.

I am trying this code to destroy and dispose anything on the model that is a material, geometry and texture map on the imported model before I import a new one but the memory in task manager for the Chrome tab does not really go down and sequentially loading a new model after destroying the old one doesn’t help.

Is there anything I missed here?

if (this.loadedObject != null) {
      // NOTE This will dispose all materials from the GPU (make sure to dispose outside of traverse though)
      const disposables = [];

      this.loadedObject.traverse((child) => {
        if (child.material) {
          disposables.push(child);
        }
      });
      console.log("disposables: ", disposables);
      disposables.forEach((child) => {
        //child.parent.remove(child);
        child.material___needle.dispose();

        if (child.material instanceof THREE.MeshStandardMaterial) {
          console.log("material: ", child.material);
          for (const key in child.material) {
            if (key.toLowerCase().includes("map") && child.material[key]) {
              console.log(`disposing: ${key}: `, child.material[key]);
              if (child.material[key] instanceof THREE.Texture) {
                console.log(child.material[key], "was texture");
                child.material[key].dispose();
              }
            }
          }
        }
      });
      if (this.loadedObject.children.length > 0) {
        this.loadedObject.children.forEach((child) => {
          console.log("child: ", child);
          console;
          if (child.geometry) {
            console.log("disposing child geo: ", child.geometry);
            child.geometry.dispose();
          }
        });
      }

      GameObject.destroy(this.loadedObject);

      console.log("Destroyed last model");
    }

I made a live demo of this here EPM Model Viewer

Hit the load model button repeatedly to see that when the gameobject is destroyed, the memory is not cleared and when we load a new model the memory increases. This can be seen in the Taskmanager process for the tab on windows.

Is there something I am missing here for memory cleanup?

Hi, I’m looking into this and see if it reproduces here.

You load the file with loadSync(url) ?

Regarding dispose: You can try calling the destroy function destroy(rootObject, true, true) directly, the third argument is dispose and false by default.

import { destroy } from "@needle-tools/engine"

// root = your Object root, true = recursive, true = dispose
destroy(root, true, true);

This recursively walks through the object hierarchy and disposes the resources (removes all references).

Btw you can also use the chrome memory profiler to sample and see who allocates and references your data and to debug issues like these. Arbeitsspeicherbereich – Übersicht  |  Chrome DevTools  |  Chrome for Developers

I tested the destroy method just now without gameobject.destroy, just the normal destroy from Needle and the memory still would go up even with both bools set to true. If the third argument was true then any time I used loadsync again on the same .glb file it would load the model but all textures would be black or missing I think.

Hi @robyer1

I’m seeing the same behaviour with vanilla three.js 169 and just using GLTFLoader load and memory is rising. I know this wasn’t the case in 162.

Black textures: I didnt see this behaviour here using the third argument set to true

1 Like

Ah that’s good to know, I wonder if anything is missed in memory cleanup when calling destroy? Let me know if I can test anything.

Can you try removing the GLTF object log? This does keep the data in browser memory too

I’ve also found a bug where a reference to the loaded glTF file was kept in memory if the glTF file didn’t have any script components where the code responsible for clearing the reference was then never called. This will be fixed in the next version!

With both changes above (when you do not log the whole gltf object to the console) + the engine fix memory will properly be freed

Edit: Released the fix in 4.3.2-beta.1

Thanks I’ll test this tomorrow when I’m in office and confirm it fixes it. I’ll make sure to remove any console logs of the gltf.

Ok thanks. With the console logs I’m getting the same allocation issue in vanilla three.js and also in Needle Engine, that’s how I noticed you’re also logging the glTF object in your project