Pixi.js Memory Management and Garbage Collection

Web applications utilizing Pixi.js require diligent memory management to maintain high frame rates and prevent browser crashes caused by memory leaks. This article explores how Pixi.js handles resource allocation and garbage collection, detailing the manual destruction of sprites, the lifecycle of textures on the GPU, and how Pixi’s built-in automatic garbage collector assists in freeing system resources.

Sprite Destruction and CPU Memory

When you remove a sprite from the render stage using stage.removeChild(sprite), the sprite is only unlinked from the scene graph. It remains in system memory (CPU) because JavaScript’s native garbage collector cannot reclaim it if references to it still exist in your code.

To properly dispose of a sprite, you must call its destroy() method. By default, calling sprite.destroy() frees up the sprite’s internal references, making it eligible for JavaScript garbage collection. However, you can pass options to this method to control how associated resources are handled:

sprite.destroy({
    children: true,     // Recursively destroys all children of this container
    texture: true,      // Destroys the sprite's texture reference
    baseTexture: true   // Destroys the underlying image source and unloads it from the GPU
});

Using these options ensures that not only the sprite container is freed, but also the heavy graphical assets linked to it.

Texture vs. BaseTexture on the GPU

In Pixi.js, memory is split between system RAM (CPU) and video RAM (GPU). Understanding the distinction between Texture and BaseTexture is critical for memory management:

If you destroy a Texture without destroying its BaseTexture, the image data remains resident in the GPU memory. To completely purge an image from the GPU, you must call baseTexture.dispose() or texture.destroy(true).

The Automatic Texture Garbage Collector

Pixi.js features an automated system called the TextureGarbageCollector (managed by the renderer) to prevent GPU memory bloat from inactive textures.

Instead of keeping all loaded textures in WebGL memory indefinitely, the garbage collector periodically scans active textures. If a texture has not been used in a render pass for a specified number of frames, the collector automatically unbinds and unloads the texture from the GPU.

You can configure the behavior of the texture garbage collector via the renderer settings:

// Example configuration for Pixi.js WebGL renderer
renderer.textureGC.mode = PIXI.GC_MODES.AUTO; // Enables automatic GC
renderer.textureGC.maxIdle = 3600;            // Number of frames a texture can be idle before removal
renderer.textureGC.checkCountMax = 600;       // How often (in frames) the GC runs its check

When the automatic garbage collector unloads a texture, the data is removed from the GPU but remains in the CPU’s system memory. If the application requests that texture again, Pixi.js automatically re-uploads the image to the GPU on the next render frame.

Asset Management with Assets (Pixi.js v7+)

In modern versions of Pixi.js, the Assets class is the preferred tool for loading and managing resources. It automates much of the manual memory management:

By utilizing Assets.unload() and explicitly passing destruction flags to your sprites, you can maintain precise control over your application’s memory footprint and ensure consistent performance across all devices.