【问题标题】:Memory leak using google charts with ajax使用带有 ajax 的谷歌图表的内存泄漏
【发布时间】:2013-09-12 05:20:17
【问题描述】:

我对 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 毫秒,可以更快地看到这种效果。

编辑:固定内存使用统计

【问题讨论】:

  • 内存泄漏是一个已知问题,可能不是您的代码中导致它的原因。我认为这与浏览器对已删除 SVG 元素的垃圾收集有关,但我不确定。 Visualization API 开发团队正在调查此问题。
  • @asgallant 你是对的。我已将问题添加为答案,并会在允许时立即接受。我最终选择了冰沙图表,因为它正是为此目的而设计的。

标签: javascript memory-leaks google-visualization


【解决方案1】:

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

我怀疑这条线:

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

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

【讨论】:

  • 我正在查看documentation,但我没有看到任何方法。
  • 如果你找不到它,那么恐怕你运气不好,除非它是开源的,你可以修复它。如果尚未完成,您应该报告问题。
  • 是的,我实际上刚刚检查过,并且已经有几个关于此的问题。这似乎是一个错误。谢谢你的帮助。我将添加指向相关问题的链接。
  • 哦,我有个主意。您是否尝试过删除整个图表并使用新数据集重新初始化它?
  • 尝试破坏整个图表,然后重新创建。如果那不释放内存,那我真的不知道该怎么办了。
【解决方案2】:

这是一个已知的错误。 issue1issue2

【讨论】:

  • 2010 年和 2015 年发布的问题尚未修复?哇,这从谷歌很有趣。我也有页面,主要是谷歌图表,晚上它崩溃了。
【解决方案3】:

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

这是完整的答案:

Google Chart Constant Redrawing Memory Increase

【讨论】:

    【解决方案4】:

    如果您要为每次更新构建一个新图表(使用新的 google.visualization.SomeChart()) 然后当你完成 之前的实例,你必须调用clearChart()就可以了,否则内存 会积累。谷歌图表无法判断该图表已 垃圾收集,它需要一个明确的 clearChart() 调用 从 DOM 取消链接事件处理程序。

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

    【讨论】:

    • 这个答案是正确的,它应该被标记为正确的解决方案。它对我有用。当我监控我的页面时,我可以清楚地看到“节点”行下降。
    猜你喜欢
    • 1970-01-01
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多