微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ChartJs内存泄漏|渲染后,垃圾回收不会清理图表对象或数组

如何解决ChartJs内存泄漏|渲染后,垃圾回收不会清理图表对象或数组

我正在从事必须使用chartJs创建大量图表的项目。我注意到当图表数量增加到1000(页面会因计算机的内存而异)时,我的页面不断崩溃。

在使用chrome devtools进一步探讨了问题之后,似乎在创建图表后就不会对其进行垃圾收集。每个图表对象和由该对象创建的数组(标签数组,数据集数组,其中的数据数组)都保留在内存中,并且保留在内存中,不会被垃圾回收。由于当页面中的图表数量达到内存限制后不久崩溃时,由于它们不是垃圾收集,所以

如何解决此内存泄漏或触发垃圾回收?

编辑:请注意,我不想删除生成的图表。

JSFiddle用于更清晰的视图

用于生成图表的脚本如下

var COLORS = ["#265b62","#FF6361","#FFA600","#66C2A4","#EF3B2C","#67000D","#349866","#A05195","#78C679","#2B8CBE","#8C96C6","#373F52","#810F7C","#BC5090","#FF3D67","#D5B029","#CD9B9A","#EC7014","#665191","#003F5C"];

    function getLabels(numberOfLabel) {
        var labels = [];

        for (var i=1; i<= numberOfLabel; i++) {
            labels.push('Category '+i);
        }

        return labels;
    }

    function getDataSeries(labels,numberOfSeries) {

        var dataSeries = [];
        for (var i=1; i<= numberOfSeries; i++) {
            dataSeries.push(getDataObj(i,labels.length));
        }

        return dataSeries;
    }

    function getDataObj(count,numberOfLabel) {
        var seriesLabel = 'Dataset ' + count;
        var colorName = COLORS[count % COLORS.length];

        dataArray = [];

        for (var i=1; i<= numberOfLabel; i++) {
            dataArray.push(randomScalingFactor());
        }

        var dataObj = {
            label: seriesLabel,backgroundColor: colorName,borderColor: colorName,data: dataArray,fill: false,};

        return dataObj;
    }

    function getConfig(chartCount,dataPoints,barOrLineCounts) {
        var chartLabels = getLabels(dataPoints);
        var dataSeries = getDataSeries(chartLabels,barOrLineCounts);

        var chartTitle = 'Chart.js Line Chart Count ' + chartCount;
        var chartType = 'line';
        var config = {
            type: chartType,data: {
                labels: chartLabels,datasets: dataSeries
            },options: {
                // ===============performance tweaks==========================================
                parsing: false,spanGaps: true,elements: {
                    line: {
                        tension: 0,// disables bezier curves for line datasets
                        fill: false,stepped: false,borderDash: []
                    },point: {
                        radius: 2 // default = 3,set 0 to disable and gain performance
                    }
                },animation: false,// ===============performance tweaks==========================================
                responsive: true,title: {
                    display: true,text: chartTitle,},tooltips: {
                    mode: 'index',intersect: false,hover: {
                    mode: 'nearest',intersect: true
                },scales: {
                    xAxes: [{
                        display: true,ticks: {
                            autoSkip: false,maxRotation: 45,minRotation: 45,sampleSize: 35
                        },stacked: chartType === 'bar',scaleLabel: {
                            display: true,labelString: 'Month'
                        }
                    }],yAxes: [{
                        display: true,ticks: {
                            // setting min and max will gain performance as chartjs wont have to compute this.
                            min: 0,max: 100
                        },labelString: 'Value'
                        }
                    }]
                }
            }
        };

        return config;
    }


    function generateCharts(chartCount,barOrLineCounts) {
        for (var i=1; i<= chartCount; i++) {
            var ctx = document.getElementById('canvas'+i).getContext('2d');

            var myLine = new Chart(ctx,getConfig(i,barOrLineCounts));
        }
    }

    window.onload = function() {

                var chartCount = 1;
        var dataPoints= 20;
        var barOrLineCounts = 10;


        $('#chartType').val("${chartType}");

        generateCharts(chartCount,barOrLineCounts);
    };

    var xCount =  2;
    function addChart() {
        var chartCount = 1;
        var dataPoints= 20;
        var barOrLineCounts = 10;

        var ctx = document.getElementById('canvas'+xCount).getContext('2d');
        var myLine = new Chart(ctx,getConfig(xCount,barOrLineCounts));

        xCount = xCount + 1;
    }

    function randomScalingFactor() {
        return Math.random() * 100;
    }

为测试用例提供HTML示例。

<div class="panel-body">
   <button id="addChart" onclick="addChart()">Add Chart</button><br><br>
   <div id="container">
      <div id="chart1" class="col-sm-12">
         <canvas id="canvas1">
         </canvas>
      </div>
      <div id="chart2" class="col-sm-12">
         <canvas id="canvas2">
         </canvas>
      </div>
      <div id="chart3" class="col-sm-12">
         <canvas id="canvas3">
         </canvas>
      </div>
      <div id="chart4" class="col-sm-12">
         <canvas id="canvas4">
         </canvas>
      </div>
      <div id="chart5" class="col-sm-12">
         <canvas id="canvas4">
         </canvas>
      </div>
...
...
...
      <div id="chart17" class="col-sm-12">
         <canvas id="canvas17">
         </canvas>
      </div>
      <div id="chart18" class="col-sm-12">
         <canvas id="canvas18">
         </canvas>
      </div>
      <div id="chart19" class="col-sm-12">
         <canvas id="canvas19">
         </canvas>
      </div>
      <div id="chart20" class="col-sm-12">
         <canvas id="canvas20">
         </canvas>
      </div>
   </div>
</div>

解决方法

为了对图表进行垃圾收集,必须确保没有剩余的引用。

使用chartInstance.destroy()来清除Chart.js对图表对象的内部引用:documentation

调用new Chart(...)时,您必须将该引用存储在某个位置(例如,存储在数组中),并在完成后在其上调用.destroy()。不要忘记也从数组中删除引用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。