Fix memory leak: replace JSDOM with lightweight DOM stub + graphics pool - #1
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Running p5.js sketches that call
createGraphics()every frame caused unbounded heap growth (76MB → 700MB+). Two root causes:createGraphics()call allocated a new native Cairo instance, they were were released and therefore never garbage collected.Key Changes
p5b-dom.js(new file) —P5bDOMclass with a minimal DOM stub we have full ownership over. It canvases so lifecycle is fully under our control. This DOM stub is not exported in the library’s public API.p5b.jsP5bDOM_gfxPool(Map keyed byWxHdimensions) —createGraphics()is overridden to return a pooledp5.Graphicsobject when one is available, making zero new Cairo allocations after the first frametoFrame()now uses Cairo’s nativedrawImage+toBuffer("raw")for scaling (BGRA→RGBA swap) instead of a JS pixel loop over the full source canvasp5.Graphics.remove()to safely detach from the DOM stub without crashing in headless environments_emitRuntimeErrorto always emit (was silently swallowing errors when no listener was attached)package.jsonp5b-dom.jstofilesjsdomdependencyResult
Heap memory stabilizes around 13–19MB (normal GC sawtooth), RSS tends to cap around 100–125mb before garbage collection kicks in. Previously heap memory grew monotonically at ~80KB/frame, and RSS memory grew several mb per second leading to OOM errors after a few hours.