我正在IBM的网站上阅读这篇文章(http://www.ibm.com/developerworks/web/library/wa-memleak/)关于JavaScript中的内存泄漏,当我遇到一个看起来不太喜欢泄漏的内存泄漏时:
<html>
<body>
<script type="text/javascript">
document.write("Program to illustrate memory leak via closure");
window.onload=function outerFunction(){
var obj = document.getElementById("element");
obj.onclick=function innerFunction(){
alert("Hi! I will leak");
};
obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
// This is used to make the leak significant
};
</script>
<button id="element">Click Me</button>
</body>
</html>
我了解所有其他泄漏,但这个突出了。它说DOM和JavaScript对象之间存在循环引用,但我没有看到它。
任何人都可以对此有所了解吗?
编辑:链接似乎已被取消(我甚至刷新了我已经用完的页面并且它已经关闭)。这是Google的缓存(只要持续时间为http://webcache.googleusercontent.com/search?q=cache:kLR-FJUeKv0J:www.ibm.com/developerworks/web/library/wa-memleak/+memory+management+in+javascript&cd=1&hl=en&ct=clnk&gl=us&client=firefox-a)答案 0 :(得分:6)
对onclick
的{{1}}的赋值创建了一个函数闭包,它保留了innerFunction
范围内变量的值。这允许innerFunction
中的代码引用它上面的变量,并且是javascript的理想特性(某些其他语言没有的东西)。
innerFunction
范围内的变量包括innerFunction
。因此,只要存在对此闭包的引用,就会保留该闭包中的变量。它是一次性内存使用,因此它不会随着时间的推移而累积,因此通常不会很重要。但是,如果您将大数据放入其中一个变量中,然后预期它将被释放,那么“是”您将使用比预期更多的浏览器内存。
这可能导致问题的是在这个特定的例子中,你在JS&lt; ==&gt;之间有一个循环引用。 DOM。在JS中,您保留了(在函数闭包中)对obj
变量中DOM对象的引用。在DOM对象中,您保留了对JS代码和函数闭包的引用以及对onclick属性的赋值。一些较旧的浏览器非常愚蠢,即使你从DOM中删除“元素”对象,循环引用也会使垃圾收集器不再释放内存。这在现代浏览器中不是问题,因为它们足够智能以查看此循环引用,并且如果没有外部引用它仍然可以释放该对象。
在您的特定代码中,您实际上没有创建泄漏,因为该元素仍在DOM中。 bigString只是你附加到DOM元素的一大块数据,它将保留在那里直到你删除该属性或删除DOM对象。这不是泄漏,只是存储。
如果你这样做,这将成为IE6泄漏的唯一方法:
obj
现在,您已经从DOM中删除了对象(稍后会在代码中删除)并且可能期望释放与其关联的所有内存,但循环引用会阻止它在IE6中发生。您可以通过执行以下操作来解决此问题:
<html>
<body>
<script type="text/javascript">
document.write("Program to illustrate memory leak via closure");
window.onload=function outerFunction(){
var obj = document.getElementById("element");
obj.onclick=function innerFunction(){
alert("Hi! I will leak");
};
obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
// This is used to make the leak significant
};
// called later in your code
function freeObject() {
var obj = document.getElementById("element");
obj.parentNode.removeChild(obj); // remove object from DOM
}
</script>
<button id="element">Click Me</button>
</body>
</html>
或者,如果你不需要在闭包中使用<html>
<body>
<script type="text/javascript">
document.write("Program to illustrate memory leak via closure");
window.onload=function outerFunction(){
var obj = document.getElementById("element");
obj.onclick=function innerFunction(){
alert("Hi! I will leak");
};
obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
// This is used to make the leak significant
};
// called later in your code
function freeObject() {
var obj = document.getElementById("element");
obj.onclick=null; // clear handler and closure reference
obj.parentNode.removeChild(obj); // remove object from DOM
}
</script>
<button id="element">Click Me</button>
</body>
</html>
引用,你可以完全用以下方法从闭包中取消引用:
obj
实际上,在泄漏的内存使用量很大的情况下,这只是一个有意义的问题。
答案 1 :(得分:0)
由于IE6错误导致内存泄漏。
obj
引用来自innerFunction
的{{1}}和onclick
引用innerFunction
,因为它从外部范围捕获obj
。