调整字号

JavaScript 闭包引起的内存泄漏(IE)

在 IE8 以及更早的版本中,由于两种垃圾收集算法并存,所以会发生循环引用的问题,引发内存泄漏,例如下面的代码:

function assignHandler() {
    var element = document.getElementById('someElement');
    element.onclick = function() {
        alert(element.id);
    };
}

以上代码中创建了一个匿名函数(闭包),并赋给 element 作为事件处理程序,因此 element 引用了这个匿名函数,而匿名函数中又引用了 element 对象,导致了循环引用,这两个对象被引用次数永远无法减少到 0,而由于老版本 IE 对 BOM 和 DOM 对象都采用引用计数的垃圾收集机制,所以这两个对象占用的内存就永远得不到回收。

可以通过改变代码的写法解决这个问题:

function assignHandler() {
    var element = document.getElementById('someElement'),
        id = element.id;
    element.onclick = function() {
        alert(id);
    };
    element = null;
}

设置另外一个变量 id 是为了解除匿名函数对 element 的引用,这样就不存在循环引用,但是内存泄露的问题仍然有,因为只要闭包存在,外层函数的所有变量都会被保存到闭包的作用域链中,尽管闭包只引用了 id,其他变量也会被保留,直到匿名函数被销毁。导致的结果就是,element 一直引用着这个 DOM 节点,即使节点从文档中移除以后,节点占用的内存也不会回收,因为 element 仍在引用这个节点。所以最后设置 elementnull,解除引用,是为了保证内存能够正常回收。也可以设置 element.onclicknull,解除对匿名函数的引用,这样闭包占用的内存也会被回收。

为了更好地使用内存,写 JS 的时候对一些不再使用的变量,还是给它设置为 null 手动解除引用比较好,特别是一些全局变量。

还没有评论,沙发空缺中……
flight