[英]javascript memory leak with HTML5 Canvas getImageData in Chrome browser for mac OSX
此问题已在新的chrome版本(版本35.0.1916.114)中得到修复
在chrome for mac osx中 ,CanvasRenderingContext2D #getImageData函数会使内存泄漏,我该如何避免这个问题,这里是测试用例和结果,它只发生在chrome浏览器中,safari可以
<!DOCTYPE html>
<html>
<head>
<title>CanvasRenderingContext2D#getImageData bug in chrome</title>
<script type="text/javascript">
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 i = 0;
while(i++ < 100){
var c = g.getImageData(0,0,1000, 1000);
delete c;
}
}
function toDataURL(){
var i = 0;
while(i++ < 100){
var c = g.canvas.toDataURL();
delete c;
}
}
</script>
</head>
<body onload="init()">
<button onclick="getImageData()">call getImageData 100 times - then memory will grow, can't GC</button>
<button onclick="toDataURL()">call toDataURL 100 times - it is OK</button><br>
<canvas id='canvas' width='600px' height='500px'/>
</body>
</html>
您的问题不在于getImageData
函数。 这是分配保存getImageData
的变量的方式,用于
创建泄漏
。
问题是delete 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
信息的内存将保留在那里,直到函数返回。 由于image data
是一个非常大的对象,并且它越大,画布尺寸越大,在巨大的循环中(假设500个循环或以上,这取决于机器)将在函数返回和垃圾收集器之前导致内存溢出被触发。
我推荐以下文章: 编写快速,内存高效的JavaScript 。 它解释得很好,易于阅读。
解决!!!
现在我们知道只有在函数返回后才会触发垃圾收集器,我想到的一个解决方案是将调用getImageData
的函数推迟几分之一毫秒。 这样我们保证函数在每次getImageData调用后返回。
我尝试了下面的代码,它甚至可以进行10000次迭代! 花了很多时间来完成,但它完成了,没有内存泄漏!)
自己尝试一下:
<!DOCTYPE html>
<html>
<head>
<title>CanvasRenderingContext2D#getImageData bug fixed</title>
<script type="text/javascript">
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");
}
</script>
</head>
<body onload="init()">
<button onclick="test()">call getImageData several times</button><br>
<canvas id='canvas' width='600px' height='500px'/>
</body>
</html>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.