gma*_*man 5 html javascript memory-leaks
这段代码在浏览器中导致内存泄漏是否正确?
/**
* @param {Canvas2DRenderingContext} ctx
* @param {string} url
*/
function loadImageDrawIntoCanvas(ctx, x, y, url) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, x, y);
}
img.src = url;
};
Run Code Online (Sandbox Code Playgroud)
我的理解是因为img是一个DOM元素,因为我用img.onload浏览器将JavaScript附加到它上面,所以永远不会垃圾收集它.要纠正我需要清除img.onload的内容
/**
* @param {Canvas2DRenderingContext} ctx
* @param {string} url
*/
function loadImageDrawIntoCanvas(ctx, x, y, url) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, x, 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;
};
Run Code Online (Sandbox Code Playgroud)
只要浏览器正确实现,它就不应该是泄漏。
旧版本的 Internet Explorer(7 及更早版本)的 GC 无法处理 JS 和 DOM 节点之间的循环引用。因此,有很多指南建议在删除 DOM 节点之前清除事件侦听器,并且 jQuery 会自动执行此操作。(注意:其他浏览器可能在某些时候出现过 GC 错误,但旧版 IE 是最有名的。)
这里有趣的部分是 GC 需要知道onload将来是否会再次被触发。
我刚刚尝试使用与您发布的代码类似的代码将 275 MB 的图像渲染到画布上,并且 Chrome 不会泄漏。(相比之下,如果我将图像存储在循环之外的数组中,则保留 275 MB。)Firefox 可能会泄漏[一些?],但这很难说,因为它的内存开销比 Chrome 高得多。
为什么?
onload既loadImageDrawIntoCanvas完成执行,又没有剩余的引用img。img在浏览器实现方面,他们做了一些功能上相当于在调用时增加引用计数,并在触发img.src=后减少引用计数。Chrome针对onload此类泄漏有两项测试 ( 1、2 )。