The Processing API should continue to rely on explicit user calls to dispose() for PGraphicsOpenGL objects rather than relying on automatic garbage collection. While a finalizer could act as a safety net, it is insufficient for managing high-turnover native OpenGL resources.
Why the Leak Occurs
The leak happens because of the mismatch between managed memory and unmanaged video memory. When createGraphics() is called, the application allocates native textures and frame buffers on the GPU (VRAM). The managed object representing these resources in Java or C# is small, meaning the Garbage Collector (GC) may not feel enough pressure to trigger a collection for a long time. Consequently, the native textures remain allocated in VRAM, leading to out-of-memory (OOM) crashes even when system RAM usage appears low.
Strategy for Resource Management
To prevent leaks while maintaining backward compatibility, developers must follow these rules:
- Explicit Disposal: Always call
dispose() as soon as the PGraphics object is no longer needed, especially in loops or state-switching logic.
- Scope Management: If a graphics object is temporary, wrap its logic in a try-finally block to ensure disposal occurs even if an error is thrown.
- Avoid Frequent Recreation: Avoid calling
createGraphics() inside the draw() loop. Initialize the object once and reuse it.
Automatic vs. Manual Disposal Analysis
Automating the disposal via a finalizer is problematic for OpenGL contexts for several reasons:
- Nondeterminism: The GC does not guarantee when it will run. In high-performance sketches, VRAM can fill up long before the GC decides to reclaim the small wrapper objects.
- Thread Affinity: OpenGL commands often must be executed on the main thread or the render thread. Finalizers run on a background GC thread, which can cause the
glDelete calls to fail or crash the driver.
- Performance Spikes: Mass reclamation of textures during a sudden GC cycle can cause significant frame stutters (jank).
Verification Steps
To verify if your sketch is leaking, you can use the following pattern to monitor your VRAM usage:
// Test pattern for leak detection
for (int i=0; i<1000; i++) {
PGraphicsOpenGL pg = createGraphics(width, height, P2D);
// ... perform operations ...
pg.dispose(); // Ensure this prevents the climb
}
Note: Monitoring VRAM requires OS-specific tools (like Task Manager or Windows) as standard IDE profiles may not show GPU memory accurately.