为什么这段 js 代码出现内存泄露

wolfer20
  • 123
function attachEvents() {  
    var element = document.getElementById("myID");  
    element.onclick = function() {  
        alert("Element clicked");  
    }  
};  
attachEvents(); 
回复
阅读 5.2k
5 个回答
justjavac
  • 47.7k
✓ 已被采纳

该代码创建了一个引用循环

函数引用了 elementelement 又引用了函数。

变量元素包含函数的引用(归于 onclick 属性)。 同时,函数保持一个 DOM 元素的引用(提示:函数内部可以访问元素,因为闭包)。

所以 JavaScript 垃圾收集器不能清除元素或是函数,因为他们被相互引用。 大部分的 JavaScript 引擎对于清除循环应用都不够聪明。

解决办法:避免那些闭包,或者不去做函数内的循环引用。

function attachEvents() {
    var element = document.getElementById("myID");
    element.onclick = function() {
        //Remove element, so function can be collected by GC
        delete element;
        alert("Element clicked");
    }
};
attachEvents();

谢谢 @沙之守护 的提醒,原文有误:delete 不能够删除变量,参见我在 sf 发表的博文 javascript 中的 delete,应该写 element = null


TODO:明天继续更新……

参考:http://justjavac.com/named-function-expressions-demystified.html#jscript-memory-management

GrandSong
  • 168

好久没有研究内存泄漏的课题了。姑且猜猜吧。

attachEvents 原本是一次性执行结束的,但其中包含了一个匿名的函数——那个监听器,结果它就被这个监听器“绑架”了(不能安心地驾鹤西去)。

而监听器又被绑定给了element对应的DOM对象。DOM对象只要还在网页中,那么就一直有效。

但我不太清楚:

  • element变量真的没有被自动回收?它指向了DOM对象后就完成使命了啊。
  • 这种程度的“内存泄漏”有多大危害?
  • 另外,是不是所有浏览器的GC都对此束手无策?
zhenchaozhu
  • 110

内存泄漏是closure的原因造成的。闭包是由函数和构建函数的环境所组成的。 按理说,函数运行完成后,内部变量会被销毁。但是看这段代码,attachEvent函数内部返回了click函数,构造了一个闭包,这就导致了element变量会被onclick函数所引用。因此javascript垃圾回收器并不会回收element变量。 除了element=null的方法外,还可以把函数写在外面来避免。

function attachEvent() 
{ 
    var obj = document.getElementById("XXX"); 
    obj.onclick=onclickHandler; 
} 
function onclickHandler(){ 
    //do something 
}

这段代码会引起内存泄露啊。。。。我经常这么做。。。。晕了!

这个研究方向不错,很支持。JS高手可以来我找兼职

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏