将img.onload事件处理程序留在那里是否会导致内存泄漏?

5

这段代码在浏览器中会导致内存泄漏,这个说法正确吗?

/**
 * @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;
};

我的理解是因为是一个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;
};
1个回答

3
只要浏览器正确实现,就不应该出现泄漏。
旧版本的Internet Explorer(7及更早版本)具有无法处理JS和DOM节点之间循环引用的GC。有很多指南建议在删除DOM节点之前清除事件侦听器,因为这个原因,而jQuery会自动执行此操作。(注:其他浏览器可能在某些时候也有错误的GC,但旧版IE是最著名的一个。)
有趣的部分在于,GC需要知道是否将来会再次触发“onload”。
我刚刚尝试使用类似于您发布的代码的方式将275 MB的图像渲染到画布上,Chrome不会泄露。(相比之下,如果我将图像存储在循环外的数组中,则会保留275 MB。)Firefox可能会泄漏[一些?],但很难确定,因为它的内存开销比Chrome高得多。
为什么?
  • 在JavaScript端,onloadloadImageDrawIntoCanvas都完成执行,并且没有剩余对img的引用。
  • 在浏览器实现方面,当您调用img.src=时,它们执行了与增加img的引用计数相当的功能,并在onload被触发后将其减少。Chrome对这些泄漏有两个测试(12)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接