flekschas / regl-scatterplot

Scalable WebGL-based scatter plot library build with Regl
https://flekschas.github.io/regl-scatterplot/
MIT License
185 stars 21 forks source link

fix: unbind all retainers when instance is destroyed #135

Closed fspoettel closed 1 year ago

fspoettel commented 1 year ago

Write one to two sentences summarizing this PR

This PR fixes scatterplot.destroy() to properly remove all event listeners bound during instance creation.

Description

What was changed in this pull request?

Why is it necessary?

Destroyed scatterplot instances are currently retained in memory in full (including the allocated KDBush indexes and the webGL context), which leads to memory leaks in applications that create and destroy scatterplots frequently. This happens because there are some event handlers still bound to (detached) DOM elements, so the garbage collection skips the whole thing. The behavior can be observed as follows:

Adjust the example to call destroy after a timeout.

setTimeout(() => {
  scatterplot.destroy();
  // scatterplot needs to be a let binding for this to work
  scatterplot = undefined;
  canvas.parentNode.removeChild(canvas);
}, 2000);

Open the Memory tab in chrome devtools and open the example. After the canvas is removed, perform a manual garbage collection and take a heap snapshot. You will see that the instance and a canvas element is still held in memory, with the retainers pointing to certain event handlers:

Screenshot 2023-06-14 at 17 53 37

Open a new tab and repeat with the fixes applied. When looking at the snapshot now, the instance and canvas are no longer present:

Screenshot 2023-06-14 at 17 57 36

Fixes #___

Checklist

flekschas commented 1 year ago

That's a lot for putting together the PR! I wonder how I missed this haha.

flekschas commented 1 year ago

New version (v1.6.10) with the fix is out.