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:
- Remove the mesh from the parent scene.
- Dispose of the geometry associated with the mesh.
- Dispose of the texture(s) mapped to the material.
- 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
- Reusability: If multiple materials share the same texture, do not dispose of the texture until you are sure no other active materials are using it.
- Re-uploading: Once a texture is disposed, you cannot use it again. If you need it later, you must create a new texture instance and load the image again.
- Render Loop: Ensure you do not call
.dispose()inside your active requestAnimationFrame render loop unless you are explicitly discarding an asset, as allocating and deallocating memory mid-render will cause noticeable performance drops.