2007年6月15日

JScript的内存泄漏

JScript Memory Leaks in Microsoft IE

当一个系统没有妥善地管理它的内存分配时,就被称为内存泄漏,内存泄漏是一个bug,这问题会导致性能下降和运行错误。

微软的Internet Explorer有许多的泄漏问题,最严重莫过于与JScript的交互作用了。当一个Dom对象包含一个对JavaScript对象的引用时(比如一个事件句柄函数event handling function), 并且那个JavaScript对象包含了对那个Dom对象的引用,那么一个环状结构形成了。这本质并不是一个问题。在这时如果没有其他的引用DOM对象和事件句柄时,那么垃圾回收器(一个自动的内存资源管理器)将收回他们的内存,允许它们的空间被再次的分配。垃圾回收可以理解那个环状结构,并不会对它们感到困惑。不幸地是,IE的DOM结构不受JScript管理,它有它自己的内存管理器,它的内存管理器不理解那个环状结构,这导致它变的很困惑,这导致了当环状结构发生的时候,内存回收不再出现。内存不再被回收被称作泄漏,随着时间过去,这会导致内存最终穷尽。内存空间已被用满,导致浏览器死掉。

我们可以对上述进行论证。在第一个程序里,队列测试1,我们将增加10000个DOM对象(span对象),与此同时,删除最近的10个对象。当你运行它,你会发现在windows任务管理器的性能页观察PF(页面文件)使用情况为平稳的正常。PF的改变使用率可以指示内存分配效率.

接下来,运行第二个程序,队列测试2,它的结果不再与测试1相同了,唯一的变动是它对每个对象增加了一个click handler,在Mozilla和Opera中,PF使用保持平稳,但在IE中我们看到PF稳步地增加,内存泄漏导致了每秒数兆字节的增加。通常这个泄漏是不值得注意的。但是Ajax技术变得流行,单页停留时间变的很长, 页面更多的变化,导致失败变得普遍。

IE不能做好它的工作去回收环状结构,这任务落到了我们的身上,如果我们明确地打碎环状机构,那么IE就能回收内存了。根据微软所说,闭包(closures )会引起内错泄漏,这当然是严重错误的,但是这导致微软给了程序员们一个不好的建议去应对微软的bug。这关闭了从DOM方很容易解决问题的那一面,而交给了事实上不能解决问题的JScript方面。

当我们不再使用一个对象时,我们必须清除它所有的event handlers来破坏循环引用,所有我们必须要做的就是将每个event handler属性设置为null值,这可以明确的进行,又或者我们可以写一个通用的净化函数。

净化程序将一个引用DOM对象作为参数,它循环元素所有属性,如果发现任何函数,就将其设为null。这将破坏循环引用,允许内存再生。这也将元素的派生元素,这将很好清除循环引用。净化函数对Mozilla和Opera是无害的,它应用于IE。净化程序应该在移除任何元素时被调用,在removeChild方法,和设置innerHTML属性的之前使用。

function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}

最后我们运行第三个程序,队列测试3,净化程序在删除DOM元素之前被调用。

特别声明,文章翻译于JScript Memory Leaks
版权由原作者所有。

1 条评论:

匿名 说...

I should email my girlfriend about this.