为什么这是JavaScript中的内存泄漏?
我在IBM网站上阅读这篇关于JavaScript内存泄漏的文章()时,遇到了一个看起来不像是泄漏的内存泄漏:为什么这是JavaScript中的内存泄漏?,javascript,memory-management,memory-leaks,Javascript,Memory Management,Memory Leaks,我在IBM网站上阅读这篇关于JavaScript内存泄漏的文章()时,遇到了一个看起来不像是泄漏的内存泄漏: <html> <body> <script type="text/javascript"> document.write("Program to illustrate memory leak via closure"); window.onload=function outerFunction(){ var obj = document.getE
<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>
编写(“通过闭包说明内存泄漏的程序”);
window.onload=函数outerFunction(){
var obj=document.getElementById(“元素”);
obj.onclick=函数innerFunction(){
警惕(“嗨!我要泄密”);
};
obj.bigString=newarray(1000.join)(newarray(2000.join)(“XXXXX”));
//这是用来使泄漏明显
};
点击我
我理解所有其他的泄密,但这一个很突出。它说DOM和JavaScript对象之间有一个循环引用,但我没有看到
有人能解释一下吗
编辑:链接似乎已被删除(我甚至刷新了我打开的页面,但它已关闭)。这是Google的缓存(只要它持续:)对
innerFunction
的onclick
的赋值创建了一个函数闭包,该闭包保留innerFunction
范围内的变量的值。这允许innerFunction
中的代码引用上面的变量,这是javascript的一个理想特性(其他一些语言没有)
innerFunction
范围内的变量包括obj
。因此,只要存在对该闭包的引用,该闭包中的变量就会被保留。它是一次性内存使用,因此不会随时间累积,因此通常不重要。但是,如果你将大数据放入其中一个变量,然后期望它被释放,那么“是的”,你将使用比预期更多的浏览器内存
在这个特定的示例中,这可能会导致问题,在JS和DOM之间有一个循环引用。在JS中,您在obj
变量中保留了对DOM对象的引用(在函数闭包中)。在DOM对象中,您保留了对JS代码和函数闭包的引用以及对onclick属性的赋值。一些较旧的浏览器非常愚蠢,即使您从DOM中删除“element”对象,循环引用也会阻止垃圾收集器释放内存。这在现代浏览器中不是问题,因为它们足够聪明,可以看到这个循环引用,并且在没有外部引用的情况下仍然可以释放对象
在您的特定代码中,您实际上没有创建泄漏,因为元素仍然在DOM中。bigString只是附加到DOM元素的一大块数据,它将一直保留在那里,直到您删除该属性或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>
实际上,这只是在少数情况下的一个有意义的问题,因为泄漏的内存使用量可能非常大
这是由于IE6错误导致的内存泄漏
obj
引用了onclick
中的innerFunction
,并且innerFunction
引用了obj
,因为它从外部范围捕获了obj
。不仅仅是你。我在这里也看不到循环引用。你的链接不起作用?您的DOM对象obj
引用innerFunction
innerFunction
,依次通过闭包引用obj。您应该能够通过将obj.onclick设置为null onunload来避免内存泄漏。感谢您指出Nico和Juan。我看这个网站在过去20分钟内被关闭了。我甚至刷新了我以前打开的标签,它已经关闭了。我发布了谷歌缓存版本的价值。很抱歉。请看我的答案和我的评论,谢谢胡安!顺便说一句,该链接现在似乎已备份。该解决方案删除了单击处理程序,您将失去功能。解决方法是在卸载时将其移除。您不需要同时删除两个引用,只需删除其中一个。也就是说,您不需要从DOM中删除元素。IBM站点(在他们将其取下之前)提到,解决方法是在设置所有内容后设置obj=null。只有当我从DOM中删除对象并打算销毁该对象时,该解决方法才删除了单击处理程序。如果您希望对象保持在周围,那么与它相关联的内存应该保持在周围-这不是泄漏。@Adam-在上面的示例中,将obj设置为null与bigString的关系没有多大关系。您的对象上仍然有bigString作为属性,并且所有内存仍在使用中。它将删除JSDOM之间的循环引用,因此如果您稍后从DOM中删除obj,那么它将得到适当的释放。这可以防止这种情况。但是,我想澄清的问题是,如果稍后移除对象,这只是一个泄漏
<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>
<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
obj = null; // kills the circular reference, obj will be null if you access if from innerFunction()
};
</script>
<button id="element">Click Me</button>
</body>
</html>