Frontmatter
| id | 8961 |
| title | Fix: Memory Leak in Neo.component.Canvas due to missing destroy() |
| state | Closed |
| labels | bugai |
| assignees | tobiu |
| createdAt | Feb 3, 2026, 2:01 PM |
| updatedAt | Feb 3, 2026, 2:12 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8961 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | 8930 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Feb 3, 2026, 2:12 PM |
Fix: Memory Leak in Neo.component.Canvas due to missing destroy()
tobiu added parent issue #8930 on Feb 3, 2026, 2:01 PM

tobiu
Feb 3, 2026, 2:10 PM
Input from Gemini 3 Pro:
✦ I have fixed the memory leak in
Neo.component.CanvasandNeo.component.Sparkline.Changes:
src/worker/Canvas.mjs: AddedunregisterCanvasto remove canvas references from the worker's internal map.src/component/Canvas.mjs:
- Implemented
destroy()to callunregisterCanvasif the canvas was registered.- Updated
afterSetMounted()to callunregisterCanvaswhen the component is unmounted (value === false).src/canvas/Sparkline.mjs:
- Added
unregisterremote method to cleanup the renderer's specific state (active render loops, item maps).src/component/Sparkline.mjs:
- Implemented
destroy()to callrenderer.unregister.- Updated
afterSetMounted()to callrenderer.unregisteron unmount.Outcome:
OffscreenCanvascontexts and worker-side render loops are now properly cleaned up when a component is destroyed or unmounted (e.g., viaremoveDom: true). This prevents memory leaks and ensures long-term stability.
tobiu assigned to @tobiu on Feb 3, 2026, 2:11 PM
tobiu closed this issue on Feb 3, 2026, 2:12 PM
Neo.component.Canvasis missing adestroy()method. While it correctly registers the canvas with the worker on mount, it fails to unregister it on destruction.Consequence: The Canvas Worker retains
OffscreenCanvascontexts, render loops, and data structures indefinitely, leading to a memory leak and potential GPU process crash over time as views are created and destroyed.Task:
destroy()insrc/component/Canvas.mjs.destroyCanvas(or similar unregister) message to the Canvas Worker.destroyCanvashandler insrc/worker/Canvas.mjs(and specifically insrc/canvas/Sparkline.mjsif it maintains its own map) to clean up the internal state and stop render loops.