【问题标题】:Leaving a handler on img.onload is a memory leak?在 img.onload 上留下处理程序是内存泄漏?
【发布时间】:2016-09-01 19:09:51
【问题描述】:

这段代码导致浏览器内存泄漏是否正确?

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

我的理解是,因为 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;
};

【问题讨论】:

    标签: javascript html memory-leaks


    【解决方案1】:

    应该不是泄漏,只要浏览器正确实现即可。

    旧版本的 Internet Explorer(7 和更早版本)的 GC 无法处理 JS 和 DOM 节点之间的循环引用。因此,有很多指南建议在删除 DOM 节点之前清除事件侦听器,而 jQuery 会自动执行此操作。 (注意:其他浏览器可能在某些时候有错误的 GC,但旧的 IE 是著名的。)

    这里有趣的部分是 GC 需要知道onload 将来是否会再次被触发。

    我刚刚尝试使用与您发布的代码类似的代码将 275 MB 的图像渲染到画布上,并且 Chrome 没有泄漏。 (相比之下,如果我将图像存储在循环之外的数组中,则保留 275 MB。)Firefox 可能会泄漏 [一些?],但很难判断,因为它的内存开销比 Chrome 高得多。

    为什么?

    • 在 javascript 方面,onloadloadImageDrawIntoCanvas 都完成了执行,并且没有剩余对 img 的引用。
    • 在浏览器实现方面,他们在功能上相当于在您调用img.src= 时增加img 上的引用计数,并在触发onload 时减少它。 Chrome 对这类泄漏有两个测试(12)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-13
      • 1970-01-01
      • 2012-07-01
      • 2015-06-14
      • 1970-01-01
      • 2018-12-18
      • 2012-10-29
      • 2012-05-31
      相关资源
      最近更新 更多