2016-05-06 30 views
4

这段代码在浏览器中导致内存泄漏是否正确?在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.src = url; 
}; 

我的理解是,因为IMG是一个DOM元素,因为我安装的JavaScript将其与img.onload浏览器将不会垃圾回收这一点。为了纠正我需要清除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

它不应该是一个漏,只要它是由浏览器正确实施。

旧版本的Internet Explorer(7和earler)有一个GC无法处理JS和DOM节点之间的循环引用。有很多指南指出在删除DOM节点之前清除事件监听器,jQuery自动执行此操作。 (注意:其他浏览器在某些时候可能已经有了匆忙的GC,但以前的IE是着名的)。

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

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

为什么?

  • 在JavaScript的一面,onloadloadImageDrawIntoCanvas都完全执行,到img没有剩余的引用仍然存在。
  • 在浏览器实现方面,他们做了一些功能上等同于当您调用img.src=时递增img的引用计数,并且在启动onload后递减引用计数。 Chrome对这类泄漏有两种测试(1,2)。