如何解决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 举报,一经查实,本站将立刻删除。