您的问题不在于getImageData函数.这是分配保存getImageData的变量的方式,用于创建泄漏.

问题是删除c将失败(删除不影响变量名称),浏览器静默返回false.

请尝试使用c = null.尝试在for循环外声明c变量,以避免在循环的每个步骤中重新创建变量.

这是修改后的代码:

function getImageData(){

var i = 0;

var c;

while(i++ < 100){

c = g.getImageData(0,0,1000, 1000);

// c = null; // <= check UPDATE to see why this doesn't work as expected

}

}

function toDataURL(){

var i = 0;

var c;

while(i++ < 100){

c = g.canvas.toDataURL();

// c = null; // <= check UPDATE to see why this doesn't work as expected

}

}

我在同一个浏览器中完全尝试了代码,并在开发人员工具中使用内存配置文件,我可以看到内存被垃圾收集器完全清除.

检查开发人员工具中的内存时间轴(Ctrl Shift i).

要启用内存配置文件,您需要使用标志–enable-memory-info启动Chrome.

更新:

正如我在评论中已经说过的那样,垃圾收集通过回收不再可访问的内存块(对象)来工作.

当函数返回时,c指向的对象自动可用于垃圾收集,因为没有任何东西可以引用它.

关于null如何工作也存在误解.将对象引用设置为null不会使对象“为空”.它将对象引用设置为null.

因此,在这种情况下,分配用于存储每个getImageData信息的内存将保留在那里,直到函数返回.由于图像数据是一个非常大的对象,并且它越大,画布尺寸越大,在巨大的循环中(假设500个循环或以上,这取决于机器)将在函数返回和垃圾收集器之前导致内存溢出被触发.

解决!!!

现在我们知道只有在函数返回后才会触发垃圾收集器,我想到的一个解决方案是将调用getImageData的函数推迟几分之一毫秒.这样我们保证函数在每次getImageData调用后返回.

我尝试了下面的代码,它甚至可以进行10000次迭代!花了很多时间来完成,但它完成了,没有内存泄漏!)

自己尝试一下:

CanvasRenderingContext2D#getImageData bug fixed

var g;

function init(){

g = document.getElementById('canvas').getContext('2d');

g.fillStyle = "blue";

g.fillRect(10, 10, 100, 100);

g.fillStyle = "green";

g.fillRect(60, 60, 100, 100);

}

function getImageData(){

var c = g.getImageData(0,0,1000, 1000);

}

var total = 0;

var iterations = 100;

function test(){

var i = 0;

while(i++ < iterations){

setTimeout(function(){

getImageData();

total++;

//console.log(total);

if(total == iterations){

alert("" + total+" getImageData functions were completed!!!")

}

}, 0.01); // defer

}

alert("" + (i-1) + " iterations completed. Wait for the return of all getImageData");

}

call getImageData several times

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐