-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Memory leak fixes #724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory leak fixes #724
Conversation
…AF never stops; 2) scene2d.destroy should destroy the traces (cherry picked from commit 8f6f2dd)
src/plots/plots.js
Outdated
| // remove modebar | ||
| if(fullLayout._modeBar) fullLayout._modeBar.destroy(); | ||
|
|
||
| if(fullLayout._plots) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Gl context deletion should be already taken care of via Plots.cleanPlot which is currently called in Plots.supplyDefaults here and more explicity in Plotly.purge here.
Maybe something is up with the gl2d clean method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@etpinard I was chasing a point pick regression but back on this now. The root call is a Plotly.newPlot. It does call supplyDefaults and cleanPlot. But basePlotModules is [] empty so it doesn't even reach the point of testing if there is a _module.clean metod. I'm carrying on looking, based on your hint, but wanted to mention it in case it rings a bell.
P.S. In fact, oldFullLayout looks like an empty object. I'm swimming upstream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... looks like plots.purge deletes gd._fullLayout just before Plotly.plot is called (the latter of which then calls supplyDefaults which calls cleanPlot) so by the time cleanPlot is called, there's no longer information about what to clean.
I'm in a bit of a conundrum as there's a big amount of statefulness and I'm concerned that a purported fix from me (e.g. not delete gd._fullLayout in purge so the info stays around) has unintended, undesirable consequences, besides the fact that it would allow proper working of the _module.clean loop. So I'd rather get input @etpinard before shoehorning in something that looks like a fix.
Plotly.newPlot = function(gd, data, layout, config) {
gd = getGraphDiv(gd);
Plots.purge(gd); // <= this deletes gd._fullLayout
return Plotly.plot(gd, data, layout, config); // <= cleanPlot would rely on gd._fullLayout
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so by the time cleanPlot is called, there's no longer information about what to clean.
Wow. That's bad. Nice catch.
I think the best solution at the moment would be to add
// remove gl contexts
Plots.cleanPlot([], {}, fullData, fullLayout);to Plotly.newPlot before it calls Plots.purge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @etpinard! This
Plotly.newPlot = function(gd, data, layout, config) {
gd = getGraphDiv(gd);
// remove gl contexts
Plots.cleanPlot([], {}, gd._fullData || {}, gd._fullLayout || {});
Plots.purge(gd);
return Plotly.plot(gd, data, layout, config);
};
seems to go ahead and ultimately call scene2d destroy method which has my few lines of trace line disposals. I'll double-check via remeasuring the memory footprint, but for that test I have to cherrypick it into the local branch which also has the undo history limit.
|
@monfera thanks for looking into this! |
…ce dispose loop; null -> delete
|
@etpinard I pushed the change you suggested, and the pick fix (just brought forward the trace dispose loop), so I think it's ready for review. |
| gd = getGraphDiv(gd); | ||
|
|
||
| // remove gl contexts | ||
| Plots.cleanPlot([], {}, gd._fullData || {}, gd._fullLayout || {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
@monfera would you adding a test case for checking that Plotly.newPlot does clear existing gl contexts similar to the one for Plots.cleanPlot ?
Thanks in advance.
|
@monfera Looks good! Thanks again for catching that |
…rencing of the GL context or its own canvas
|
Great tests! Thanks @monfera !! |
Commit c123ebc helps a lot - not only with a significantly reduced (though not yet fully eliminated) memory leak, but also, causes a
stopfor the point picker requestAnimationFrame loop, so the purportedly idempotentplotNewfunction doesn't leave behind an orphaned, CPU eating rAF loop with potentially large arrays.It may be that part of the residual leakage is related to the rAF acting as a closure with variable capture: even if the rAF is stopped by causing
stop = truevia the intended destroy sequence, maybe some state is still retained. Check this among other things.Unrelated to the leakage, we identified the rAF based approach as something we might want to improve upon.
PR is WIP not only because it's not a full fix and it's as yet untested, but also the code will probably need to be more generic (e.g. now it shoots for
_scene2dbut the 3D case may be analogous).