使用this/self-reference执行javascript闭包会导致内存泄漏



根据我对内存泄漏的理解,在闭包中引用范围外的var将导致内存泄漏。

但是,创建一个"that"var以保留"this"引用并在闭包中使用它也是一种常见的做法,尤其是在事件中。

那么,做这样的事情是怎么回事:

SomeObject.prototype.createImage = function(){
    var that = this,
        someImage = new Image();
    someImage.src = 'someImage.png';
    someImage.onload = function(){
        that.callbackImage(this);
    }
};

这难道不会给项目增加一点漏洞吗?

是的,是的,它确实会导致内存泄漏,至少在某些浏览器中是这样(猜测是哪种)。这是一个更令人信服的理由,可以信任各种可用的框架之一,并通过其机制设置所有事件处理程序,而不是像那样直接添加"DOM 0"事件处理程序。

InternetExplorer(至少在9之前,可能包括9)内部有两种内存分配机制(至少):一种用于DOM,另一种用于JavaScript(好的JScript)。他们彼此不理解。因此,即使释放了DOM节点,也不会释放示例中的任何闭包内存。

编辑—哦,我提到框架的原因是,它们通常包括试图缓解这个问题的代码。避免将任何内容附加到DOM节点属性是最安全的方法之一。例如,所有值得担心的浏览器(包括古老的IE版本)都有将事件处理程序附加到DOM节点的替代方法。

在黑暗中拍摄,但我认为:

someImage.onload = function(){
    that.callbackImage(this);
    someImage.onload = null
}

将清除that 留下的"内存泄漏"

IE曾经有一段时间,涉及DOM元素的循环引用(通常在将函数分配给侦听器时由闭包形成)会导致内存泄漏,例如

function foo() {
  var someEl = document.getElementById('...');
  someEl.onclick = function() {...};
}

然而,我认为它们已经得到了足够的修复或修补,除非测试另有显示,否则它们可以被忽略。还有很多方法可以避免这种闭包,因此即使它们是一个问题,也可以解决(例如,不要创建涉及DOM元素的循环引用)。

编辑

使用库或任何其他附加侦听器的方法仍然可以创建循环引用和内存泄漏,例如在IE:中

function foo() {
  var el = document.getElementById('d0');
  // Create circular reference through closure to el
  el.attachEvent('onclick', function(){bar(el);});
}
function bar(o) {
  alert(o == window.event.srcElement);  // true
}
window.onload = foo;

上面使用attachEvent添加了一个监听器(几乎所有框架都将用于IE<9,包括jQuery),但仍然创建了一个涉及DOM元素的循环引用,因此会在某些版本的IE中泄漏。因此,仅使用库并不能解决问题,您需要了解原因并避免它们。

最新更新