Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Chart Constant Redrawing Memory Increase

I'm redrawing the chart based on new data each second, and it works and looks great, but I notice it increase memory like 1 MB usage each second. Any way to fix this? I notice if I just have static charts, then the memory stabilizes, but once I add constant redrawing (in order to update data), the memory usage never stops.

At first I thought it was because I was creating a new instance of the chart each time, so I change the code so it was only redrawing the same instance each time, but that didn't help much at all.

Anyone know how to fix it? Do I need to dump the old chart first somehow?

google.setOnLoadCallback(test);

var chart;
var chartOptions;
var chartCreate;

function test() {
    chart = new google.visualization.DataTable();
    chart.addColumn('string', 'Lorem');
    chart.addColumn('number', 'Ipsum');
    chart.addRows([
            ['', 0]
    ]);
    chartOptions = {};
    chartCreate = new google.visualization.LineChart(document.getElementById('chartDiv'));
          chartCreate.draw(chart, chartOptions);
    ]);
}

function test2() {
    chart.removeRows(0, 5);
    for (var i = 0; i < dataSpaceArray.length; ++i) {
        chart.addRow([dataTimeArray[i], dataSpaceArray[i], dataSpeedArray[i]]);
    }
        chartCreate.draw(chart, chartOptions);
}

setTimeout(test2,1000)
like image 887
zen Avatar asked Sep 14 '13 20:09

zen


2 Answers

I've solved this by globaly store the chart. Before draw the chart, you need to check if chart has been instantiated. If not, create the new chart object else call clearChart() method before draw it. Like this:

//Store all chart objects in a global array to avoid memory leak
var charts = [];

function drawChart(chartName, element, data, chartOptions) {
   if (charts[chartName] === undefined || charts[chartName] === null) {
          charts[chartName] = new google.visualization.LineChart(group);
   } else {
          charts[chartName].clearChart();
   }
   charts[chartName].draw(dataTable, chartOptions);
}
like image 108
truongnguyen1912 Avatar answered Sep 26 '22 11:09

truongnguyen1912


Had same issue, was able to fix it by adding a few lines to Google's clearChart() function.

W.clearChart = function() {

    //this fixes the leak
    hv = {};
    iv = {};
    jv = {};

    ...
};

More Details:

  1. Here's the Google file I made the change to:

https://www.google.com/uds/api/visualization/1.0/4086f2e8fc632adc52e6d6795a5637a4/format+en,default,corechart.I.js

  1. Download this file, make the change mentioned above. In your code, add a script tag to load above file from your webserver and comment out the following line:

    // google.load('visualization', '1', { packages: ['corechart'] });

  2. The memory will go up but will come back down on it's own after a few minutes.

  3. I'm using clearChart() but if you don't want to clear the chart, then create your own function (e.g. memoryLeakFix()) and call it periodically.

  4. Here's a test page (the 1.js is the modified file from step 1). It basically creates new chart and redraws every 100ms. You will see memory go up but hit "Stop" link to stop the redrawing and wait a few minutes and memory will come down.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.js"      type="text/javascript"></script>
  <script src="https://www.google.com/jsapi"                                          type="text/javascript"></script>

  <script src="1.js"                                          type="text/javascript"></script>


  <script type="text/javascript">

      //init google charts
//        google.load('visualization', '1', { packages: ['corechart'] });
      google.load('visualization', '1', { packages: ['table'] });

  </script>


</head>
<body>

<a href='#' onclick='stop()'>Stop</a>
  <div class='chart'></div>

  <script>

      var chart; var table;

      function createChart(container)
      {
          if(chart != undefined)
              chart.clearChart();

          //init chart
          chart = new google.visualization.LineChart(container[0]);

          //init chart data
          if(table == undefined)
          {
              table = new google.visualization.DataTable();

              table.addColumn('datetime', 'Time');
              table.addColumn('number', 'Value');

              var count = 0;

              //periodically add rows
              setInterval(function()
              {
                  //add row
                  table.addRows([ [new Date(), count++]]);    
              }, 1000);


          }
      }


      //start redrawing
      var id = setInterval(function()
      {
          createChart($('.chart'));

          drawChart();
      }, 100);

      //stop redrawing
      function stop()
      {
          clearInterval(id);
      }

      //draw chart
      function drawChart()
      {
          chart.draw(table, { curveType: "function",

              width:      250, 
              height:     250,
              pointSize:  1,
              legend:     { position: 'none' },
              chartArea: { 'width': '90%', left: 50 },
          });
      }

  </script>   
</body>
</html>
like image 32
Alex Avatar answered Sep 26 '22 11:09

Alex