How to Free GPU Memory in Three.js Using Texture Dispose

This article explains how to properly release GPU memory in Three.js by explicitly disposing of textures that are no longer needed. You will learn why manual memory management is necessary in WebGL, how to call the dispose() method on textures and materials, and see a practical code example to prevent memory leaks in your 3D WebGL applications.

Why Manual Memory Management is Necessary

In standard JavaScript applications, the garbage collector automatically reclaims memory when variables go out of scope. However, in Three.js, WebGL resources such as textures, geometries, and render targets are allocated directly on the GPU. The JavaScript garbage collector cannot see or manage GPU memory.

If you remove a mesh from your scene but do not explicitly dispose of its resources, the data remains allocated on the graphics card, leading to severe memory leaks and eventual application crashes.

How to Dispose of a Texture

To free up the GPU memory allocated for a texture, you must call the .dispose() method directly on the texture instance.

// Dispose of a single texture
myTexture.dispose();

Calling .dispose() sends a signal to the WebGL rendering context to delete the texture buffer from the GPU. Once disposed, the texture can no longer be rendered.

A Complete Cleanup Workflow

Disposing of a texture alone is often not enough because the texture is usually bound to a material, which in turn is bound to a mesh. To completely clean up a mesh and its texture from memory, you should follow these steps:

  1. Remove the mesh from the parent scene.
  2. Dispose of the geometry associated with the mesh.
  3. Dispose of the texture(s) mapped to the material.
  4. Dispose of the material itself.

Here is a reusable JavaScript function demonstrating how to safely clean up a mesh and all of its associated GPU resources, including textures:

function removeAndDisposeMesh(scene, mesh) {
    // 1. Remove the mesh from the scene
    scene.remove(mesh);

    // 2. Dispose of the geometry
    if (mesh.geometry) {
        mesh.geometry.dispose();
    }

    // 3. Dispose of the materials and textures
    if (mesh.material) {
        if (Array.isArray(mesh.material)) {
            mesh.material.forEach(material => disposeMaterial(material));
        } else {
            disposeMaterial(mesh.material);
        }
    }
}

function disposeMaterial(material) {
    // Check for common texture maps and dispose of them
    const textureKeys = ['map', 'lightMap', 'bumpMap', 'normalMap', 'specularMap', 'roughnessMap', 'metalnessMap', 'emissiveMap'];
    
    textureKeys.forEach(key => {
        if (material[key] && typeof material[key].dispose === 'function') {
            material[key].dispose();
        }
    });

    // Dispose of the material itself
    material.dispose();
}

Important Considerations