问题
I'm fairly new to javascript and I'm having trouble finding a memory leak in some code which updates a google chart each second with ajax data.
My code (simplified to a small test case):
function TimeLine(id, max) {
this.chart = new google.visualization.LineChart(document.getElementById(id));
this.vals = new google.visualization.DataTable();
this.vals.addColumn('number', 'Index');
for (var i = 2; i < arguments.length; i++) {
this.vals.addColumn('number', arguments[i]);
}
this.numCols = arguments.length - 2;
this.max = max;
this.index = 0;
this.resourceOptions = {
'title': 'Memory allocation',
'width': 360,
'height': 300
};
}
TimeLine.prototype.Add = function () {
if (this.vals.getNumberOfRows() > this.max) {
this.vals.removeRow(0);
}
var row = [this.index];
for (var i = 0; i < arguments.length; i++) {
row.push(arguments[i]);
}
this.vals.addRow(row);
this.chart.draw(this.vals, this.options);
this.index++;
};
function onLoad() {
window.Timeline = new TimeLine('gauges', 15, 'Alloc');
drawCharts();
}
function drawCharts() {
window.Timeline.Add(window.Timeline.index%3);
setTimeout(drawCharts, 1000);
}
google.load('visualization', '1.0', {
'packages': ['corechart']
});
google.setOnLoadCallback(onLoad);
I'm using chrome Version 29.0.1547.62 on 64 bit Ubuntu.
I wrapped the chart in an object to (hopefully) make it easier for me to reason about scope and garbage collection since I'm not quite used to the JS scoping rules. I've seen many questions on SO which are similar, but as far as I can tell my code shouldn't produce a leak. Using the memory timeline I can see the memory climb each time drawCharts is called and most of that memory seems to be gc'd, but after around an hour I'm up to 300 MB for that tab, and it just keeps climbing until the tab crashes. The goal is to be able to keep this tab up for extended periods as a monitoring system for the current load on one of our servers, but currently I can only keep it up for a few hours before it gets killed.
I tried using the heap snapshot in the profile tab, and if I compare the snapshot before and after a few calls to drawCharts it seems like the leaked objects are SVG elements from the chart itself, but it's possible I'm interpreting those results incorrectly.
I've reproduced the problem:
http://jsfiddle.net/dv5nK/4/
After about 20 mins, the about:memory page in chrome will start to show high memory consumption around 150 MB for me. This effect can be seen faster by shortening the setTimeout to 100 ms.
EDIT: fixed memory usage stat
回答1:
This is a known bug. issue1 issue2
回答2:
If you are building a new chart for each update (with new
google.visualization.SomeChart()
) then when you are done with the previous instance, you must callclearChart()
on it, otherwise memory will accumulate. Google Charts can't tell that the chart has been garbage collected, and it needs an explicit clearChart() call to unlink event handlers from the DOM.
source: https://github.com/google/google-visualization-issues/issues/1021
回答3:
What I notice is that, event listeners are not being removed so elements are not being released from memory.
I suspect this line:
if (this.vals.getNumberOfRows() > this.max) {
this.vals.removeRow(0);
}
Is there any way to make sure that you are removing all event listeners attached to the row you are removing?
回答4:
I had the same issue with memory usage from Google charts. Was able to fix my issue by modifying the clearChart() function in Google code.
Here is the full answer:
Google Chart Constant Redrawing Memory Increase
来源:https://stackoverflow.com/questions/18686041/memory-leak-using-google-charts-with-ajax