这段代码在浏览器中导致内存泄漏是否正确?
/**
* @param {Canvas2DRenderingContext} ctx
* @param {string} url
*/
function loadImageDrawIntoCanvas(ctx,x,y,url) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img,y);
}
img.src = url;
};
我的理解是因为img是一个DOM元素,因为我用img.onload将JavaScript附加到它上面,浏览器永远不会垃圾收集它.要纠正我需要清除img.onload
/**
* @param {Canvas2DRenderingContext} ctx
* @param {string} url
*/
function loadImageDrawIntoCanvas(ctx,y);
img.onload = null; // detach the javascript from the Image
img = null; // needed also so the closure doesn't keep
// a reference to the Image?
}
img.src = url;
};
最佳答案
它不应该是泄漏,只要它由浏览器正确实现.
旧版本的Internet Explorer(7和earler)有一个GC,无法处理JS和DOM节点之间的循环引用.有很多指南建议在删除DOM节点之前清除事件监听器,因为jQuery会自动执行此操作. (注意:其他浏览器可能在某些时候有过非常好的GC,但旧的IE是着名的.)
这里有趣的部分是GC需要知道onload是否会在将来再次被激活.
我刚尝试使用与您发布的代码类似的代码将275 MB的图像渲染到画布,Chrome不会泄漏. (相比之下,如果我将图像存储在循环外的数组中,则会保留275 MB.)Firefox可能会泄漏[某些?],但很难分辨,因为它的内存开销远远高于Chrome.
为什么?
>在javascript端,onload和loadImageDrawIntoCanvas都完成执行,并且没有剩余的对img的引用.
>在浏览器实现方面,当你调用img.src =时,它们在功能上等同于增加img上的引用计数,并在onload被触发时减少它. Chrome对这些类型的泄漏进行了两次测试(1,2).