【问题标题】:Memory leak in google line charts谷歌折线图中的内存泄漏
【发布时间】:2017-05-10 02:15:14
【问题描述】:

我一直在对 Google 图表库中的内存泄漏进行大量研究。没有发现任何对我的情况有帮助的东西。不知道到目前为止这个更新是什么。我看到谷歌图表开发团队正在尝试修复它并发布新的更新。

我正在使用折线图,数据来自 websockets。不断更新。

提前致谢

P.S 下面是我用来从 websockets 获取数据的代码。当套接字连接时,drawChart 函数每秒被调用一次。意味着整个折线图都被重绘了

function drawVisualization() {

        var data = new google.visualization.DataTable();
        data.addColumn('string', 'data');
        data.addColumn('number', 'date');

        var data_test = new google.visualization.DataTable();
        data_test.addColumn('string', 'data test');
        data_test.addColumn('number', 'date test');

        for(var i=0; i<valueArr.length; i+=2) {

          if (i>=120) {
            data.removeRow(0);
            valueArr.splice(0, 2);
            timeArr.splice(0, 2);
          }

          data.addRow([timeArr[i], valueArr[i]]);
        }

        for(var i=1; i<valueArr.length; i+=2) {

            if (i>=120) {
              data_test.removeRow(0);
              valueArr.splice(0, 2);
              timeArr.splice(0, 2);
            }

            data_test.addRow([timeArr[i], valueArr[i]]);
        }

        //console.log(valueArr);
        // use a DataView to 0-out all the values in the data set for the initial draw
        var view = new google.visualization.DataView(data);
        var view_test = new google.visualization.DataView(data_test);

        // Create and draw the plot
        var chart = new google.visualization.LineChart(document.getElementById('visualization'));
        var chart_test = new google.visualization.LineChart(document.getElementById('visualization_test'));

        var options = {
            title:" ",
            width: 960,
            height: 460,
            bar: { groupWidth: "40%" },
            legend: { position: "bottom" },
            animation: {"startup": true},
            curveType: 'function',
            lineWidth: 3,
            backgroundColor: '#f9f9f9',
            colors: ['red'],
            tooltip: {
                textStyle: {
                  color: 'red',
                  italic: true
                },
                showColorCode: true
            },
            animation: {
                startup: true,
                easing: 'inAndOut',
                //duration: 500
            },
            vAxis: {
                title: '',
                gridlines: {
                  count: 8,
                  color: '#999'
                }
                /*minValue: 1.3,
                maxValue: 1.4*/
            },
            hAxis: {
              title: 'Time Stamp'
            },
        };

        //stay in sockets
        var runOnce = google.visualization.events.addListener(chart, 'ready', function () {
            google.visualization.events.removeListener(runOnce);
            chart.draw(data, options);
            chart_test.draw(data, options);
        });

        chart.draw(view, options);
        chart_test.draw(view_test, options);
}

function init() {
try {
    socket = new WebSocket(portal);
    //console.log('WebSocket status '+socket.readyState);
    socket.onopen = function(msg) {
        //console.log("Welcome - status "+this.readyState);
    };


    socket.onmessage = function(msg) {
        parseData(msg);
        drawVisualization();

    };

    socket.onclose = function(msg) {
        console.log("Disconnected - status "+this.readyState);
    };
}
catch(ex){
    console.log(ex);
}
}

【问题讨论】:

  • 根据数据量和设置的选项,绘制图表可能需要一秒钟以上的时间——建议等到第一次绘制完成,然后再尝试再次绘制——以了解何时绘制图表绘制完成,监听'ready'事件,或者'animationfinish'如果使用动画——drawVisualization中可能还有其他问题——你应该只创建一次图表,然后使用新数据重新绘制相同的图表实例...
  • 请检查我刚刚附在上面的代码。所以你建议我可以将 draw() 函数分离到 data.addRow() 中,并在套接字连接时定期调用 data.addRow() 。
  • 我早些时候尝试过这个解决方案。但是我在“分离代码”时遇到了一些麻烦,我在我的 drawVisualization() 函数中声明所有变量是全局的吗?还是?
  • 在上面的代码中,我试图拼接/弹出数组中的数据,但似乎这不会做任何事情。旧图表中的对象已存储在 DOM 中。
  • 我正在考虑 bind() 函数。咖喱?我对 javascript 有点陌生 :)

标签: javascript charts memory-leaks google-visualization


【解决方案1】:

从只画一张图表开始,你可以设置类似于下面的 sn-p...

应该用新数据绘制相同的图表,只有在上一次绘制完成之后......

function init() {
  var getData = true;

  var chart = new google.visualization.LineChart(document.getElementById('visualization'));
  google.visualization.events.addListener(chart, 'ready', function () {
    getData = true;
  });

  var options = {
    title:" ",
    width: 960,
    height: 460,
    bar: { groupWidth: "40%" },
    legend: { position: "bottom" },
    animation: {"startup": true},
    curveType: 'function',
    lineWidth: 3,
    backgroundColor: '#f9f9f9',
    colors: ['red'],
    tooltip: {
      textStyle: {
        color: 'red',
        italic: true
      },
      showColorCode: true
    },
    animation: {
      startup: true,
      easing: 'inAndOut',
      //duration: 500
    },
    vAxis: {
      title: '',
      gridlines: {
        count: 8,
        color: '#999'
      }
      /*minValue: 1.3,
      maxValue: 1.4*/
    },
    hAxis: {
      title: 'Time Stamp'
    },
  };

  // if you want data from previous draws, declare here...
  var data = new google.visualization.DataTable();
  data.addColumn('string', 'Time');
  data.addColumn('number', 'Value');
  // or see below...

  // msg = object with arrays from parseData
  function drawVisualization(msg) {

    // if you ** don't ** want data from previous draws, declare here instead...
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'Time');
    data.addColumn('number', 'Value');
    // ---<

    for (var i = 0; i < msg.valueArr.length; i++) {
      data.addRow([msg.timeArr[i], msg.valueArr[i]]);
    }

    chart.draw(data, options);
  }

  function parseData(msg) {
    //... declare timeArr & valueArr locally here

    return {
      timeArr: timeArr,
      valueArr: valueArr
    };
  }

  function startData() {
    try {
      socket = new WebSocket(portal);
      //console.log('WebSocket status '+socket.readyState);

      socket.onopen = function(msg) {
        //console.log("Welcome - status "+this.readyState);
      };

      socket.onmessage = function(msg) {
        if (getData) {
          getData = false;

          // pass object with arrays from parseData
          drawVisualization(parseData(msg));
        }
      };

      socket.onclose = function(msg) {
        //console.log("Disconnected - status "+this.readyState);
      };
    }
    catch(ex){
      console.log(ex);
    }
  }
  startData();
}

【讨论】:

  • 只从一张图表开始,推荐与上述类似的设置——多张图表如何发挥作用?你想保留以前通话的数据吗?如果是这样,您可能希望在行数上设置某种最大值...
  • 你注意到我的代码中有两个循环吗?在同一个数组中循环。因为我正在用来自同一个 websocket 的数据绘制 2 个图表
  • 是的,我确实在 120 秒或关闭后设置了 i>120。该数组将每秒弹出 1 个元素。
  • 看起来两个图表使用相同的数据??
  • 是的,顺便说一句,我正在尝试您建议的解决方案。它与我以前的结果相同。我不明白这将如何避免内存泄漏?
猜你喜欢
  • 2011-11-18
  • 2013-09-12
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-29
相关资源
最近更新 更多