4

我对 javascript 还很陌生,我无法在某些代码中找到内存泄漏,这些代码每秒都会使用 ajax 数据更新一个谷歌图表。

我的代码(简化为一个小测试用例):

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 元素,但我可能错误地解释了这些结果。

我已经重现了这个问题:

http://jsfiddle.net/dv5nK/4/

大约 20 分钟后,chrome 中的 about:memory 页面将开始显示对我来说大约 150 MB 的高内存消耗。通过将 setTimeout 缩短为 100 毫秒,可以更快地看到这种效果。

编辑:固定内存使用统计

4

4 回答 4

2

这是一个已知的错误。问题1 问题 2

于 2013-09-08T17:24:21.133 回答
2

如果您正在为每次更新构建一个新图表(使用 new google.visualization.SomeChart()),那么当您完成前一个实例时,您必须调用clearChart()它,否则内存会累积。Google Charts 无法判断该图表是否已被垃圾回收,它需要显式调用 clearChart() 来取消与 D​​OM 的事件处理程序的链接。

来源:https ://github.com/google/google-visualization-issues/issues/1021

于 2017-07-04T09:00:56.980 回答
0

我注意到的是,事件侦听器没有被删除,因此元素没有从内存中释放。

我怀疑这条线:

if (this.vals.getNumberOfRows() > this.max) {
    this.vals.removeRow(0);
}

有什么方法可以确保删除附加到要删除的行的所有事件侦听器?

于 2013-09-08T17:00:08.860 回答
0

我在谷歌图表的内存使用方面遇到了同样的问题。能够通过修改 Google 代码中的 clearChart() 函数来解决我的问题。

这是完整的答案:

谷歌图表常量重绘内存增加

于 2013-09-17T01:19:34.340 回答