• JScript内存泄漏/ie内存泄漏


    闭包导致了内存泄漏,至少msdn是这么说的。一直以为这是个ie6时代早已经解决的问题,从没特别留意,无意中运行了段代码才发现在ie8时代,这个问题还是存在的。找了点资料,了解一下。

    所谓的“点资料”主要是两篇文章:

    第一篇文章是在表层进行了理解,他的例子很好。第二篇文章更深入更严格,比较抽象。

    javascript内存泄漏

    按照第二篇文章提到,内存泄漏的本质就一句话:javascript权威指南认为,因为使用计数器算法,ie只有遇到循环就注定产生泄漏。后来 eri更正说“ie6处理不了的是jscript与navite object(如dom,active object)之间的ciruclar reference“(在这种情况下才使用计数器算法)。

    第一篇译言翻译在这里http://feed.yeeyan.com/articles/view/3407/10103

    说得很绕口,但形象了很多:

    “ 当一个DOM对象包涵有一个JavaScript对象(例如一个事件处理函数)的引用,同时如果这个JavaScript对象又包涵该DOM对象,那么这个循环引用就形成了。

    这种结构本质上没有问题。[此时,因为该DOM对象和这个事件处理函数并没有别的引用存在,那么垃圾回收器(一种自动的内存资源管理器)本应该把它们都回收点,并内存释放。]JavaScript的垃圾回收器能够检测到这种循环引用,并不会对他产生困惑。

    但是不幸的是,IE DOM的内存并不能被Jscript所管理。他有他自己的内存管理系统,然而这套系统并不知道循环引用,使得一切都变得混乱。这就导致了,当循环引用形成的时候,内存释放工作不能完成。”

    综上内存泄漏准确的说法是:”当碰到Closure,当我们往Native对象(例如Dom对象、ActiveX Object)上绑定事件响应代码时,一个不小心,我们就会制造出Closure Memory Leak。其关键原因,其实和前者是一样的,也是一个跨javascript object和native object的循环引用。只是代码更为隐蔽,这个隐蔽性,是由于javascript的语言特性造成的。但在使用类似内嵌函数的时候,内嵌的函数有拥有一个reference指向外部函数的scope,包括外部函数的参数,因此也就很容易造成一个很隐蔽的循环引用,例如: DOM_Node.onevent ->function_object.[ [ scope ] ] ->scope_chain ->Activation_object.nodeRef ->DOM_Node。“

    三个例子解读

    第一篇文章里的三个例子靠谱解读在这里:

    http://www.javaeye.com/topic/172344

    暂时我的看法

    在什么情况下引起泄漏?

    一般都认为是ie6才会有这个问题,但实际上在几个版本的ie里运行下面的代码会发现内存的确在增加。

    /*global setTimeout */  
               
    (function (limit, delay) {  
                   
    var queue = new Array(10);  
                   
    var n = 0;  
     
                   
    function makeSpan(n) {  
                       
    var s = document.createElement('span');  
                        document
    .body.appendChild(s);  
                       
    var t = document.createTextNode(' ' + n);  
                        s
    .appendChild(t);  
                        s
    .onclick = function (e) {  
                            s
    .style.backgroundColor = 'red';  
                            alert
    (n);  
                       
    };  
                       
    return s;  
                   
    }  
     
                   
    function process(n) {  
                        queue
    .push(makeSpan(n));  
                       
    var s = queue.shift();  
                       
    if (s) {  
                            s
    .parentNode.removeChild(s);  
                       
    }  
                   
    }  
     
                   
    function loop() {  
                       
    if (n < limit) {  
                            process
    (n);  
                            n
    += 1;  
                            setTimeout
    (loop, delay);  
                       
    }  
                   
    }  
     
                    loop
    ();  
               
    })(10000, 10);  

    如何解决这个问题:一句话废话,删除元素之前去除附在上面的函数。(咦,这句话怎么这么熟?)

    第二篇文章给出的解决方式看上去更和谐点。毕竟在js框架中,我们都会看到类似专门的回收器的代码,恐怕是因为对每段程序释放是太废时间的工作。

  • 相关阅读:
    Python数据结构与算法(几种排序)
    jquery元素节点操作
    Jquery事件委托
    Jquery事件冒泡
    jquery事件
    尺寸相关、滚动事件
    jquery属性操作
    jquery选择器
    JavaScript面向对象
    jQuery powerFloat万能浮动层下拉层插件
  • 原文地址:https://www.cnblogs.com/pricks/p/1672472.html
Copyright © 2020-2023  润新知