为什么 JavaScript 会出现内存泄漏?
我正在阅读这篇文章( http://www.ibm.com/developerworks/ web/library/wa-memleak/ )在 IBM 网站上关于 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 )
I was reading this article ( http://www.ibm.com/developerworks/web/library/wa-memleak/ ) on IBM's website about memory leaks in JavaScript when I came across a memory leak that didn't quite look liked it leaked:
<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>
I understood all the other leaks but this one stood out. It says there's a circular reference between the DOM and JavaScript object but I don't see it.
Can anyone shed some light on this?
EDIT: The link seems to have been taken down (I even refreshed the page I had up and it was down). Here's Google's cache (for as long as that lasts: 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 )
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对
innerFunction
的onclick
的赋值创建了一个函数闭包,该函数闭包保留innerFunction
范围内的变量值。这允许innerFunction
中的代码引用其上方的变量,并且是 javascript 的一个理想功能(其他一些语言没有)。innerFunction
范围内的那些变量包括obj
。因此,只要存在对此闭包的引用,该闭包中的变量就会被保留。它是一次性的内存使用量,因此不会随着时间的推移而累积,因此通常并不重要。但是,如果您将大数据放入这些变量之一,然后期望它被释放,那么“是的”您将使用比您预期更多的浏览器内存。在这个特定的示例中,这可能会导致问题,在 JS <==> 和 JS <==> 之间存在循环引用。 DOM。在 JS 中,您(在函数闭包中)在
obj
变量中保留了对 DOM 对象的引用。在 DOM 对象中,您保留了对 JS 代码的引用和函数闭包以及对 onclick 属性的赋值。一些较旧的浏览器足够愚蠢,即使您从 DOM 中删除“元素”对象,循环引用也会阻止垃圾收集器释放内存。这在现代浏览器中不是问题,因为它们足够聪明,可以看到此循环引用,并且如果没有外部引用,仍然可以释放该对象。在您的特定代码中,您实际上并未创建泄漏,因为该元素仍在 DOM 中。 bigString 只是您附加到 DOM 元素的一大块数据,它将一直保留在那里,直到您删除该属性或删除 DOM 对象。这不是泄漏,这只是存储。
在 IE6 中,这会成为泄漏的唯一方法是如果您这样做:
现在,您已经从 DOM 中删除了该对象(稍后在您的代码中),并且可能期望与其关联的所有内存都被释放,但是循环引用防止这种情况在 IE6 中发生。您可以通过执行以下操作来解决此问题:
或者,如果您不需要闭包中的 obj 引用,则可以使用以下方法完全使闭包中的引用为空:
实际上,这是只有在少数情况下,当泄漏的内存使用量可能很大时,这才是有意义的问题。
The assignment to
onclick
of theinnerFunction
creates a function closure that preserves the value of the variables that are in scope ofinnerFunction
. This allows the code ininnerFunction
to reference variables above it and is a desirable feature of javascript (something some other languages don't have).Those variables that are in scope of
innerFunction
includeobj
. So, as long as there is a reference to this closure, the variables in that closure are preserved. It's a one-time piece of memory usage so it doesn't accumulate over time and thus isn't usually significant. But, if you put big data into one of those variables, then and expected it to be freed, then "yes" you would be using more browser memory than you expected.Where this can cause problems is in this particular example, you have a circular reference between JS <==> DOM. In JS, you have preserved (in the function closure) a reference to the DOM object in the
obj
variable. In the DOM object, you have preserved a reference to the JS code and the function closure with the assignment to the onclick attribute. Some older browsers are dumb enough that even if you remove the "element" object from the DOM, the circular reference will keep the garbage collector from ever freeing the memory. This is not a problem in modern browsers as they are smart enough to see this circular reference and still free the object if there are no outside references to it.In your particular code, you haven't actually created a leak because the element is still in the DOM. bigString is just a big chunk of data you've attached to the DOM element and it will stay there until you remove that attribute or remove the DOM object. That's not a leak, that's just storage.
The only way this would become a leak in IE6 is if you did this:
Now, you've removed the object from the DOM (sometime later in your code) and probably expected all memory associated with it to be freed, but the circular reference keeps that from happening in IE6. You could work-around that by doing the following:
or, if you don't need the
obj
reference in the closure, you could null the reference from the closure entirely with this:In practice, this is only a meaningful issue in a few cases when the memory usage of a leak could be significant.
由于 IE6 错误,这会泄漏内存。
obj
从onclick
引用innerFunction
,而innerFunction
引用obj
因为它捕获obj
来自外部范围。This leaks memory due to an IE6 bug.
obj
referencesinnerFunction
fromonclick
, andinnerFunction
referencesobj
because it capturesobj
from the outer scope.