Skip to content

fix: dispose WebGL renderers and revoke blob URLs to prevent resource leaks#846

Merged
EdwardMoyse merged 2 commits into
HSF:mainfrom
GaneshPatil7517:fix/845-resource-leaks-three-manager
Mar 25, 2026
Merged

fix: dispose WebGL renderers and revoke blob URLs to prevent resource leaks#846
EdwardMoyse merged 2 commits into
HSF:mainfrom
GaneshPatil7517:fix/845-resource-leaks-three-manager

Conversation

@GaneshPatil7517
Copy link
Copy Markdown
Collaborator

Resolves #845

Three resource leaks compound over time in long-running sessions:

  1. WebGL contexts never freed -RendererManager.cleanup() removed the resize listener but never called renderer.dispose(). On re-initialization, old WebGL contexts leaked. Browsers cap contexts at ~8–16; after that, the oldest context is silently lost.

  2. Blob URLs never revoked in saveBlob -URL.createObjectURL()was called on each download butURL.revokeObjectURL()was never called, keeping blob references in memory until page unload. The` element was also permanently appended to the DOM via an IIFE.

  3. Duplicate leak in makeScreenShot - The screenshot export created its own <a> element and blob URL with the same missing cleanup pattern.

Changes

  • renderer-manager.ts - cleanup() now calls renderer.dispose() and renderer.domElement.remove() for every renderer in the list, then clears the array.

  • three-manager/index.ts - Replaced the saveBlob IIFE with a private saveBlob() method that creates a temporary <a> element, triggers the download, then revokes the object URL and removes the element via setTimeout. makeScreenShot now reuses this method instead of duplicating the pattern.

  • renderer-manager.test.ts - Added 3 test cases:

    • Dispose is called on all renderers and DOM elements are removed
    • Resize event listener is removed after init() + cleanup()
    • cleanup() does not throw when no resize handler is set

Testing
All 29 test suites / 178 tests pass (including 3 new).

… leaks

- Add renderer.dispose() and domElement.remove() calls in
  RendererManager.cleanup() to free WebGL contexts on re-initialization
- Replace saveBlob IIFE with a method that revokes object URLs after
  download and removes the temporary anchor element from the DOM
- Reuse saveBlob in makeScreenShot to eliminate duplicate blob URL leak
- Add 3 unit tests for cleanup() covering renderer disposal, resize
  listener removal, and safe no-op when no handler is set

Closes HSF#845
Copilot AI review requested due to automatic review settings March 24, 2026 16:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes long-running session resource leaks in phoenix-event-display by disposing Three.js renderers during lifecycle cleanup and revoking Blob object URLs used for downloads/screenshot export.

Changes:

  • Dispose/remove renderer DOM elements during RendererManager.cleanup() to avoid leaking WebGL contexts.
  • Refactor download logic into ThreeManager.saveBlob() and revoke Blob URLs after triggering download; reuse for screenshots.
  • Add unit tests covering renderer disposal, DOM removal, and resize listener cleanup.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/phoenix-event-display/src/managers/three-manager/renderer-manager.ts Adds renderer disposal + canvas removal during cleanup.
packages/phoenix-event-display/src/managers/three-manager/index.ts Reworks Blob download helper to revoke object URLs; reuses for screenshot export.
packages/phoenix-event-display/src/tests/managers/three-manager/renderer-manager.test.ts Adds tests for new cleanup behavior (dispose/remove/listener removal).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/phoenix-event-display/src/managers/three-manager/renderer-manager.ts Outdated
…er reuse

Keep the main WebGLRenderer alive in cleanup() since init() reuses it
via getMainRenderer(). Only secondary renderers (e.g. overlay) are
disposed. The overlay reference is cleared so stale overlay state does
not persist across re-initialization.

Without this, a cleanup() -> init() cycle would leave mainRenderer
pointing to a disposed WebGLRenderer, breaking setLocalClippingEnabled,
getLocalClipping, and any subsequent rendering.
@EdwardMoyse EdwardMoyse merged commit 36dfbec into HSF:main Mar 25, 2026
2 checks passed
@EdwardMoyse
Copy link
Copy Markdown
Member

Thank you for this!

@GaneshPatil7517
Copy link
Copy Markdown
Collaborator Author

Thank you for this!
hello @EdwardMoyse and @sponce
Thank you so much for your guidance and support! I truly appreciate it.
I’ll stay consistent and keep improving. Always happy to help whenever needed, anytime. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: WebGL and browser resource leaks in ThreeManager lifecycle (renderer disposal, blob URLs, DOM elements)

3 participants