我对javascript很新,我在某些代码中发现内存泄漏时遇到问题,这些代码每秒都会使用ajax数据更新Google图表。
我的代码(简化为小测试用例):
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);
我在64位Ubuntu上使用chrome版本29.0.1547.62。
我将图表包装在一个对象中(希望)让我更容易推理范围和垃圾收集,因为我不太熟悉JS范围规则。我在SO上看到了很多类似的问题,但据我所知,我的代码不应该产生泄漏。使用内存时间轴我可以看到每次调用drawCharts时内存爬升,并且大部分内存似乎都是gc'd,但是大约一个小时之后我就达到了300 MB的那个标签,它只是一直爬到标签崩溃。我们的目标是能够长时间保持此选项卡作为我们其中一台服务器上当前负载的监控系统,但目前我只能将其保留几小时才能被杀死。
我尝试在配置文件选项卡中使用堆快照,如果我在几次调用drawCharts之前和之后比较快照,似乎泄漏的对象是图表本身的SVG元素,但我可能会解释那些结果不正确。
我转载了这个问题:
大约20分钟后,chrome中的about:memory页面将开始为我显示大约150 MB的高内存消耗。通过将setTimeout缩短为100毫秒,可以更快地看到此效果。
编辑:固定内存使用情况
答案 0 :(得分:2)
答案 1 :(得分:1)
如果要为每次更新构建新图表(使用new
google.visualization.SomeChart()
)然后当你完成了 在上一个实例中,您必须在其上调用clearChart()
,否则请调用内存 会积累。谷歌图表无法分辨图表 垃圾收集,它需要一个明确的clearChart()调用 从DOM中取消链接事件处理程序。
来源:https://github.com/google/google-visualization-issues/issues/1021
答案 2 :(得分:0)
我注意到,事件侦听器没有被删除,因此元素不会从内存中释放。
我怀疑这一行:
if (this.vals.getNumberOfRows() > this.max) {
this.vals.removeRow(0);
}
有没有办法确保删除附加到要删除的行的所有事件侦听器?
答案 3 :(得分:0)
我对Google图表的内存使用存在同样的问题。能够通过修改Google代码中的clearChart()函数来解决我的问题。
以下是完整的答案: