Skip to content

Conversation

ahrefabhi
Copy link
Contributor

@ahrefabhi ahrefabhi commented Oct 12, 2025

Description

Fixes critical memory leaks in uPlot chart rendering that were causing memory spikes during chart re-renders and updates.

Problem

Memory profiling revealed significant memory leaks in getUplotChartOptions.ts. The function was adding multiple event listeners that were never cleaned up when charts were destroyed or re-rendered:

  1. Legend tooltip listeners - mouseenter and mouseleave events on each legend item
  2. Legend click handlers - Click events on markers and text elements for each series
  3. Global document listener - A mousemove event listener on document that accumulated on every chart render
  4. Orphaned DOM elements - Tooltip elements appended to document.body that were never removed

Each time a chart was re-rendered or updated, new event listeners were added while old ones remained attached, causing memory to grow continuously.

Solution

Implemented comprehensive event listener cleanup using uPlot's lifecycle hooks:

Changes Made

  • Added tracking system: Created _legendCleanups array in ExtendedUPlot interface to track all event listeners
  • Extracted inline handlers: Converted anonymous inline event handlers to named functions for proper cleanup
  • Implemented destroy hook: Added destroy hook to uPlot options that removes all tracked listeners
  • Enhanced component cleanup: Updated Uplot.tsx destroy callback to manually trigger all cleanup functions
  • DOM cleanup: Added removal of orphaned .legend-tooltip elements from DOM

Files Modified

  • frontend/src/lib/uPlotLib/getUplotChartOptions.ts - Main memory leak fixes
  • frontend/src/components/Uplot/Uplot.tsx - Enhanced cleanup in React component

Impact

  • Prevents memory accumulation during chart re-renders
  • Eliminates memory spikes observed in profiling
  • Improves overall application performance and stability
  • Prevents potential browser slowdown after extended use with multiple charts

5 Heap Snapshot before Fix: (10 Sec interaction between each snapshot)

image

6 Heap Snapshot after Fix: (10 Sec interaction between each snapshot)

image

@ahrefabhi ahrefabhi requested review from a team and YounixM as code owners October 12, 2025 10:43
@github-actions github-actions bot added the bug Something isn't working label Oct 12, 2025
Copy link
Member

@srikanthccv srikanthccv left a comment

Choose a reason for hiding this comment

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

Overall LGTM. We now have a clean up in two places 1. Uplot.tsx before chart.destroy() and hooks.destroy, please consolidate this or is there a reason to clean up in both places separately?

Comment on lines +459 to +461
// Initialize cleanup array for tracking all event listeners
(self as ExtendedUPlot)._legendCleanups = [];

Copy link
Member

Choose a reason for hiding this comment

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

This is not used.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants