How to Destroy a WebGL Context Properly
Managing GPU memory is crucial in web applications, yet WebGL lacks a single, native method to tear down an entire rendering context at once. This guide explains how to properly dispose of a WebGL context, manually free allocated GPU assets—including buffers, textures, and shaders—and trigger explicit context loss using standard WebGL extensions to prevent memory leaks and performance degradation.
1. Release Allocated GPU Resources
Relying solely on the browser's JavaScript garbage collector is not enough to clear GPU memory immediately. Before destroying the context, you must explicitly iterate through and delete all created WebGL resources.
- Buffers: Call
gl.deleteBuffer(buffer)for every vertex or index buffer created. - Textures: Call
gl.deleteTexture(texture)to free texture VRAM. - Renderbuffers and Framebuffers: Call
gl.deleteRenderbuffer(renderbuffer)andgl.deleteFramebuffer(framebuffer). - Shaders and Programs: Detach shaders using
gl.detachShader(program, shader), delete individual shaders withgl.deleteShader(shader), and finally remove the program withgl.deleteProgram(program).
2. Force Context Loss Using the Extension
Because WebGL contexts are tied to the underlying graphics driver,
the correct way to inform the browser that the context is dead is by
using the WEBGL_lose_context extension.
Acquiring this extension allows you to programmatically trigger the
webglcontextlost event and simulate a hardware-level
drop:
const loseContextExt = gl.getExtension('WEBGL_lose_context');
if (loseContextExt) {
loseContextExt.loseContext();
}Calling loseContext() halts all rendering operations
immediately and tells the browser to discard internal driver resources
associated with that context.
3. Clear DOM Elements and JavaScript References
Once the context has been forced to lose its state, release all remaining JavaScript references to allow the garbage collector to reclaim CPU memory:
- Remove Event Listeners: Remove any resize, render,
or context restoration listeners tied to the
<canvas>element. - Remove the Canvas: Remove the
<canvas>element from the DOM usingcanvas.remove(). - Nullify References: Set your canvas element,
context reference (
gl), extension instances, and cached assets tonull. - Reset Dimensions: Optionally set
canvas.width = 1andcanvas.height = 1to shrink the canvas backing store before dereferencing.
Complete Cleanup Example
function destroyWebGLContext(gl, canvas, resources = {}) {
// 1. Delete registered GPU resources
if (resources.textures) resources.textures.forEach(t => gl.deleteTexture(t));
if (resources.buffers) resources.buffers.forEach(b => gl.deleteBuffer(b));
if (resources.framebuffers) resources.framebuffers.forEach(fb => gl.deleteFramebuffer(fb));
if (resources.renderbuffers) resources.renderbuffers.forEach(rb => gl.deleteRenderbuffer(rb));
if (resources.programs) {
resources.programs.forEach(prog => {
const shaders = gl.getAttachedShaders(prog);
if (shaders) {
shaders.forEach(shader => {
gl.detachShader(prog, shader);
gl.deleteShader(shader);
});
}
gl.deleteProgram(prog);
});
}
// 2. Force the context to be lost
const loseContextExt = gl.getExtension('WEBGL_lose_context');
if (loseContextExt) {
loseContextExt.loseContext();
}
// 3. Clean up the DOM and shrink the drawing buffer
if (canvas) {
canvas.width = 1;
canvas.height = 1;
if (canvas.parentNode) {
canvas.parentNode.removeChild(canvas);
}
}
// 4. Clear all references
return null;
}Executing these steps in order ensures that both the CPU and GPU release all handles, preventing memory growth during dynamic canvas creation and destruction.