sam*_*sha 6 javascript memory-leaks google-chrome getimagedata html5-canvas
此问题已在新的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>
Run Code Online (Sandbox Code Playgroud)

你的问题不在于getImageData功能。这是保存变量的getImageData分配方式造成了泄漏.
问题是delete c will fail (delete doesn\'t affect variable names) and the browser silently returns false.
尝试用c = null代替。c尝试在外部声明变量for loop, to avoid recreate the variable in each step of the loop.
这是修改后的代码:
\n\nfunction getImageData(){\n var i = 0;\n var c;\n while(i++ < 100){\n c = g.getImageData(0,0,1000, 1000);\n // c = null; // <= check UPDATE to see why this doesn\'t work as expected\n } \n}\n\nfunction toDataURL(){\n var i = 0;\n var c;\n while(i++ < 100){\n c = g.canvas.toDataURL();\n // c = null; // <= check UPDATE to see why this doesn\'t work as expected\n } \n}\nRun Code Online (Sandbox Code Playgroud)\n\n我在同一个浏览器中尝试了完全相同的代码,并使用开发人员工具中的内存配置文件,我可以看到垃圾收集器完全清除了内存。
\n\n在开发者工具中检查内存时间线(Ctrl+Shift+i).
要启用内存配置文件,您需要使用标志启动 Chrome--enable-memory-info.
正如我\xe2\x80\x99ve在评论中已经说过的那样,垃圾收集通过回收不再可达的内存块(对象)来工作。
\n\n当函数返回时,该对象c指向的对象自动可用于垃圾回收,因为没有任何东西可以引用它。
对于如何运作也存在误解null。设置对象引用null doesn\xe2\x80\x99t \xe2\x80\x9cnull\xe2\x80\x9d the object. It sets the object reference to null.
因此,在这种情况下,分配用于存储每个信息的内存getImageData将保留在那里,直到函数返回。自从image data is a very large object, and it\'s larger as larger are the canvas dimensions, in huge loops (let\'s say 500 loops or above, that depends on the machine) will cause overflow in memory before the function returns and the garbage collector be triggered.
我推荐以下文章:Writing Fast, Memory-Efficient JavaScript. It\'s well explained and easy to read.
\n\n解决方案 !!!
\n\n现在我们知道垃圾收集器仅在函数返回后才会触发,我想到的一个解决方案是将调用该函数的函数延迟getImageData几分之一毫秒。这样我们就可以保证函数在每次 getImageData 调用后返回。
我尝试了下面的代码,即使迭代 10000 次它也能工作!花了很多时间来完成,但它完成了并且没有内存泄漏!)
\n\n自己尝试一下:
\n\n<!DOCTYPE html>\n<html>\n<head>\n<title>CanvasRenderingContext2D#getImageData bug fixed</title>\n<script type="text/javascript">\n\nvar g;\nfunction init(){\n g = document.getElementById(\'canvas\').getContext(\'2d\');\n g.fillStyle = "blue";\n g.fillRect(10, 10, 100, 100);\n g.fillStyle = "green";\n g.fillRect(60, 60, 100, 100);\n}\n\nfunction getImageData(){ \n var c = g.getImageData(0,0,1000, 1000); \n}\n\nvar total = 0;\nvar iterations = 100;\n\nfunction test(){\n var i = 0;\n\n while(i++ < iterations){\n setTimeout(function(){ \n getImageData();\n total++;\n //console.log(total);\n if(total == iterations){\n alert("" + total+" getImageData functions were completed!!!")\n }\n }, 0.01); // defer\n }\n alert("" + (i-1) + " iterations completed. Wait for the return of all getImageData");\n}\n</script>\n</head>\n<body onload="init()">\n<button onclick="test()">call getImageData several times</button><br>\n<canvas id=\'canvas\' width=\'600px\' height=\'500px\'/>\n</body>\n</html>\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
5771 次 |
| 最近记录: |