论坛首页 Web前端技术论坛

JSCRIPT 内存泄露

浏览 2407 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-07-04  
声明:由于本人水平有限,请各位见谅,如果有任何疑问请参阅原文,hrft:http://javascript.crockford.com/memory/leak.html
author:Douglas Crockford


当一个系统不能正确的管理它的内存分配,就称之为内存泄露,这是一种BUG,其症状包括执行效率的降低和程序运行失败。
IE包含大量的泄露,最坏的一种发生在与JSCRIPT的交互过程中。当一个DOM对象包含了一个指向JS对象的引用(例如一个事件处理函数),而该JS对象也同时包含该DOM对象的引用时,一个循环结构形成了,在JS里这并不是一个问题,在这种情况下如果没有其他的引用指向这个DOM对象和事件处理句柄,垃圾回收器(一种自动管理内存的装置)将回收他们。而不幸的是,当一个死循环发生时,内存回收就不会发生了,因此发生内存泄露,随着时间的推移,内存被耗尽,内存空间充满正在使用的CELL时,浏览器就就挂起了。

我们可以举个例子,在一个程序(queuetest1)中,我们不停的创建10000个DOM元素,与此同时,删除掉除了最近创建的10个元素外的所有元素,当你打开任务管理器查看时,你将会看到PF(page file,即页面文件)的使用率任然保持在一个几乎恒定的水平上。PF使用率的改变可以作为内存分配无效的标志(原文:Changes on PF Usage can be an indicator of memory allocation inefficiency.)。

随后,我们运行第二个程序,queuetest2,它和第一个程序做的事情几乎相同,但不同的是他为每个元素增加了一个单击事件的处理器(click handler),在Mozilla和Opera中,PF使用率几乎保持不变,而在IE中,我们可以看到因为内存的泄露而引起的PF使用率以MB/S的速度稳步增长,通常情况下这种内存泄露经常被忽视。但是随着AJAX技术变得越来越流行,造成一张页面在浏览器中停留的时间也就越长,这种情况下对同一张页面操作的增加,就更有可能造成失败。

因为IE在回收循环上的失败,这幅担子不可避免的落到了我们头上,如果我们显式的破坏循环,IE就可以成功的回收内存了。但是根据Microsoft官方的观点,闭包(closure)是引起内存泄露(memory leaks)的元凶,这当然是极端错误的观点。由此看来,在有关如何处理微软BUG方面,微软提供了非常坏的建议。事实证明了我们可以很容易的在DOM这一边上破坏循环,从而解决问题,而不大可能在JSCRIPT的那一端把死循环破坏掉。

因此,可以这样来解决上述问题:
我们在完成一个元素的操作后,必须将元素的事件处理器置空以便退出可能存在的死循环,我们可以将元素的事件处理器属性赋值为NULL来解决这个问题。这可以作为一个规范来完成,或者我们写一个通用的purge函数来完成这一任务。

purge函数可以接受一个DOM元素作为它的参数。它对元素的各个属性进行循环比较,将任何值为函数的属性置为null,这样就退出了可能存在的死循环,允许占用的资源被回收。purge函数也将检查元素的后代元素,并同样破坏它们所有可能的死循环。当然,专门为IE浏览器处理内存回收BUG而定制的purge函数运行在Mozilla和Opera上是无害的。要注意的是,应当在移除元素、移除子元素,和设定该元素的innerHTML之前调用purge函数。

下面给出purge函数的代码:
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]);       
         }   
   }
}

我们在IE上运行第三个程序queuetest3,在queuetest3中,移除DOM元素之前purge函数将会被调用。
----------------------------------------------------------------------------------------------------
update:微软宣称已经修复了这个代号为929874的问题,如果你确信你所有的用户都对微软的这个BUG修复感到满意,那么你可以不在你的程序中调用purge函数。而不幸的是,至今我们还不能作出定论,所以建议在IE6上的程序中仍然使用purge函数。

这就是web的特点,修补一个bug并不一定代表bug就再也不会存在。
   发表时间:2008-07-04  
最近工作太忙,也没怎么对文字润色,翻译得不好,请各位拍砖。
0 请登录后投票
   发表时间:2008-07-04  
看到作者是Douglas Crockford的时候 就不太想看了
看完之后 发现果然是一篇没营养的东西
原来他的解决方案就是离开页面时purge一下
0 请登录后投票
   发表时间:2008-07-04  
呵呵,附上作者的介绍:
Douglas Crockford,目前正在Yahoo任职的架构师,同时也是JSON数据交换格式的创世人。他曾在Atari公司开发了办公自动化系统,同时也完成了对于游戏和音乐的研究;曾作为Lucasfilm电影公司技术总监;在Paramount公司任职过新媒体执行主管;通常为人所知的是 communities.com的创始人兼首席执行管;他还创办了State软件公司并作为该公司CTO,这也是他发现JSON时所在的地方;他同时也对 Blissymbolics非常感兴趣,这是一种图形、象征性的语言。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics