Skip to content

Conversation

@WHOIM1205
Copy link
Contributor

Fix DRACOLoader Web Worker memory leak during GLTF loading

Summary

This PR fixes a critical memory leak caused by undisposed DRACOLoader instances created during GLTF loading.
Each GLTF load was spawning Web Workers that were never terminated, leading to unbounded worker and memory growth during normal Phoenix usage.


Problem

Multiple GLTF loading paths in ImportManager created new DRACOLoader instances per load without calling dispose().

In three.js, DRACOLoader:

  • Spawns Web Workers for DRACO decoding
  • Creates blob URLs for decoder scripts
  • Allocates decoder module memory inside workers

These resources are not garbage-collected and must be explicitly released via DRACOLoader.dispose().

As a result:

  • Each GLTF load leaked 1–4 Web Workers
  • Navigating between detector views accumulated orphaned workers
  • Long-running Phoenix sessions became increasingly slow
  • Browser tabs eventually crashed due to resource exhaustion

This issue is independent of PR #791, which addressed GPU BufferGeometry disposal, not loader lifecycle or Web Workers.


What This PR Fixes

  • Introduces a controlled lifecycle for DRACOLoader
  • Ensures DRACO Web Workers are properly terminated
  • Prevents accumulation of orphaned workers across view reloads
  • Adds explicit cleanup on manager teardown

Changes Made

Core Fix

File: packages/phoenix-event-display/src/managers/three-manager/import-manager.ts

  • Added a managed DRACOLoader lifecycle
  • Replaced per-method DRACOLoader creation with a controlled instance
  • Added cleanup() method to explicitly dispose DRACO resources
  • Updated all GLTF loading paths to use the managed loader:
    • parsePhnxScene
    • loadGLTFGeometryInternal
    • parseGLTFGeometryFromArrayBuffer

Integration

File: packages/phoenix-event-display/src/managers/three-manager/index.ts

  • Hooked ImportManager.cleanup() into ThreeManager.cleanup() to ensure proper disposal during teardown

Impact

Before After
30–120 leaked Web Workers per detector load 0 leaked workers
Memory grows with each navigation Memory released on cleanup
Browser tab degrades over time Stable long-running sessions
Silent failure mode Predictable, controlled lifecycle

This is especially important for physics analysis workflows where Phoenix is kept open for extended periods.


Test Coverage

New tests added:
packages/phoenix-event-display/src/tests/managers/three-manager/import-manager.test.ts

Tests verify:

  • DRACOLoader is lazily initialized
  • A single managed instance is reused correctly
  • dispose() is called during cleanup
  • Cleanup is safe and idempotent
  • Loader can be re-initialized after cleanup
  • Decoder path configuration is preserved

Tests run in jsdom and mock DRACOLoader to validate lifecycle behavior without spawning real workers.


Verification (Manual)

  1. Open Phoenix detector view in Chrome
  2. Navigate between ATLAS / CMS / LHCb views multiple times
  3. Observe:
    • No increase in active Web Workers (chrome://inspect/#workers)
    • Stable JS heap usage in DevTools
  4. Long-running sessions remain responsive

Notes

Signed-off-by: WHOIM1205 <rathourprateek8@gmail.com>
@WHOIM1205
Copy link
Contributor Author

hey @EdwardMoyse
Fixes a DRACOLoader lifecycle leak where Web Workers created during GLTF loading were never disposed, causing memory and worker accumulation during repeated navigation.

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.

1 participant