# When to dispose: How to completely clean up a Three.js scene

**URL:** <https://discourse.threejs.org/t/when-to-dispose-how-to-completely-clean-up-a-three-js-scene/1549>\
**Category:** Questions\
**Tags:** dispose, garbage-collection, cleanup\
**Created:** [December 31, 2017, 9:51pm UTC](https://discourse.threejs.org/t/when-to-dispose-how-to-completely-clean-up-a-three-js-scene/1549 "2017-12-31T21:51:40Z")\
**Posts on this page:** 1\
**Showing post:** 24

<div class="post-metadata">

**Author:** ![GitHubDragonFly](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/githubdragonfly/32/20752_2.png) [@GitHubDragonFly](https://discourse.threejs.org/u/GitHubDragonFly)\
**Post date:** [August 23, 2024, 9:34pm UTC](https://discourse.threejs.org/t/when-to-dispose-how-to-completely-clean-up-a-three-js-scene/1549/24 "2024-08-23T21:34:07Z")

</div>

For those who might be interested, here is the example cleanup code that removes GLTF model (`gltf_obj`) from the scene and also tries to clear GPU.

It is a slightly modified / simplified version of the function from my [GLTF Viewer](https://github.com/GitHubDragonFly/GitHubDragonFly.github.io/blob/30cd3ed33a043c96e393ad8c92ef0dade0688bda/viewers/templates/GLTF%20Viewer.html) which can be modified and/or simplified further but should cover the general idea of cleaning and disposing, depending of whether only a model is being removed from the scene or cleaning the whole scene (in which case try traversing the scene instead).

```js
      async function scene_cleanup() {
        let texture_maps = [ 'map', 'aoMap', 'alphaMap', 'bumpMap', 'displacementMap', 'envMap', 'lightMap', 'emissiveMap', 'normalMap',
          'metalnessMap', 'roughnessMap', 'anisotropyMap', 'clearcoatMap', 'clearcoatNormalMap', 'clearcoatRoughnessMap',
          'iridescenceMap', 'iridescenceThicknessMap', 'sheenColorMap', 'sheenRoughnessMap', 'specularMap',
          'specularColorMap', 'specularIntensityMap', 'thicknessMap', 'transmissionMap'
        ];

        // Remove GLTF model from the scene
        scene.remove( gltf_obj );

        renderer.clear();

        // If animation_mixer was declared and created uncomment the following lines
        //if (animation_mixer) {
        // animation_mixer.stopAllAction();

        // for ( let i = 0; i < animations.length; i++ ) {
        // animation_mixer.uncacheAction( animations[i] );
        // animation_mixer.uncacheClip( animations[i] );
        // }

        // animation_mixer.uncacheRoot( animation_mixer.getRoot() );
        //}

        if (gltf_obj.skeleton && gltf_obj.skeleton.boneTexture)
          gltf_obj.skeleton.boneTexture.dispose();

        gltf_obj.traverse( function( child ) {
          if (child.isMesh || child.isPoints || child.isLine)) {
            if (child.skeleton && child.skeleton.boneTexture)
                child.skeleton.boneTexture.dispose();

            if (child.material) {
              if (Array.isArray( child.material )) {
                child.material.forEach( mtl => {
                  if (mtl.uniforms) {
                    Object.keys( mtl.uniforms ).forEach( ( key ) => {
                      if (mtl.uniforms[key].value) {
                        let kv = mtl.uniforms[key].value;

                        if (Array.isArray( kv ) && kv.length > 0) {
                          kv.forEach( val => {
                            if (val.type && val.type === 1009) val.dispose();
                          });
                        } else {
                          if (kv.type && kv.type === 1009) kv.dispose();
                        }
                      }
                    });
                  } else {
                    for (const prop in mtl) {
                      texture_maps.forEach( tex_map => {
                        if (prop === tex_map) {
                          if (mtl[prop]) mtl[prop].dispose();
                        }
                      });
                    };
                  }

                  mtl.dispose();
                });
              } else {
                if (child.material.uniforms) {
                  Object.keys( child.material.uniforms ).forEach( ( key ) => {
                    if (child.material.uniforms[key].value) {
                      let kv = child.material.uniforms[key].value;

                      if (Array.isArray( kv ) && kv.length > 0) {
                        kv.forEach( val => {
                          if (val.type && val.type === 1009) val.dispose();
                        });
                      } else {
                        if (kv.type && kv.type === 1009) kv.dispose();
                      }
                    }
                  });
                } else {
                  for (const prop in child.material) {
                    texture_maps.forEach( tex_map => {
                      if (prop === tex_map) {
                        if (child.material[prop]) child.material[prop].dispose();
                      }
                    });
                  };
                }

                child.material.dispose();
              }
            }

            child.geometry.dispose();
          }
        });

        // If cleaning the whole scene uncomment the following lines
        //renderer.dispose();

        //while (scene.children.length > 0) {
        // scene.remove( scene.children[0] );
        //}
      }

```

This code will not be cleaning geometries / textures related to environment (they seem to be somehow cached for subsequent use).

If using a console then consider logging the renderer info so you can see how many geometries / textures are being used:

```js
        console.log( 'Memory: ', renderer.info.memory );
        console.log( 'Render: ', renderer.info.render );

```

---

_[View the full topic](https://discourse.threejs.org/t/when-to-dispose-how-to-completely-clean-up-a-three-js-scene/1549)._
