Skip to content

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

Merged
merged 4 commits into from
Jul 8, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/plots/gl2d/scene2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ proto.destroy = function() {

this.glplot = null;
this.stopped = true;

var traces = this.traces;
if(traces) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice find.

I think the gl-plot3d cleans its trace objects internally, but it would worth double checking 👍

Object.keys(traces).map(function(key) {
traces[key].dispose();
traces[key] = null;
});
}
};

proto.plot = function(fullData, calcData, fullLayout) {
Expand Down
10 changes: 10 additions & 0 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,16 @@ plots.purge = function(gd) {
// remove modebar
if(fullLayout._modeBar) fullLayout._modeBar.destroy();

if(fullLayout._plots) {
Copy link
Contributor

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?

Copy link
Contributor Author

@monfera monfera Jul 7, 2016

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.

Copy link
Contributor Author

@monfera monfera Jul 7, 2016

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
};

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Object.keys(fullLayout._plots).map(function(key) {
var plot = fullLayout._plots[key];
if(plot._scene2d) {
plot._scene2d.destroy();
plot._scene2d = null;
}
});
}

// data and layout
delete gd.data;
delete gd.layout;
Expand Down