gpt4 book ai didi

javascript - 为什么这是 JavaScript 中的内存泄漏?

转载 作者:数据小太阳 更新时间:2023-10-29 06:13:15 26 4
gpt4 key购买 nike

我在 IBM 的网站上阅读这篇关于 JavaScript 内存泄漏的文章 ( http://www.ibm.com/developerworks/web/library/wa-memleak/ ) 时,我遇到了一个看起来不太像泄漏的内存泄漏:

<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 对象之间存在循环引用,但我没有看到它。

任何人都可以阐明这一点吗?

编辑:该链接似乎已被删除(我什至刷新了我打开的页面,但它已关闭)。这是谷歌的缓存(只要它持续: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)

最佳答案

innerFunctiononclick 的赋值创建了一个函数闭包,它保留了 innerFunction 范围内的变量值。这允许 innerFunction 中的代码引用它上面的变量,这是 javascript 的一个理想特性(其他一些语言没有)。

那些在innerFunction 范围内的变量包括obj。因此,只要存在对该闭包的引用,该闭包中的变量就会被保留。它是一次性的内存使用量,因此不会随着时间的推移而累积,因此通常并不重要。但是,如果您将大数据放入这些变量之一,然后期望它被释放,那么"is"您将使用比预期更多的浏览器内存。

在这个特定示例中,这可能会导致问题,您在 JS <==> DOM 之间有一个循环引用。在 JS 中,您已经(在函数闭包中)在 obj 变量中保留了对 DOM 对象的引用。在 DOM 对象中,您保留了对 JS 代码的引用和分配给 onclick 属性的函数闭包。一些较旧的浏览器非常愚蠢,即使您从 DOM 中删除“元素”对象,循环引用也会阻止垃圾收集器释放内存。这在现代浏览器中不是问题,因为它们足够聪明,可以看到这个循环引用,并且在没有外部引用的情况下仍然释放该对象。

在您的特定代码中,您实际上并没有造成泄漏,因为该元素仍在 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>

现在,您已经从 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.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 引用,您可以使用以下方法完全取消闭包中的引用:

<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>

在实践中,这只是在少数情况下有意义的问题,因为泄漏的内存使用量可能很大。

  1. 如果您有大量数据存储为 DOM 属性,那么单个对象泄漏可能会泄漏大量数据。这通常通过不在 DOM 对象上存储大块数据来解决。将它们存储在 JS 中,您可以在其中明确控制生命周期。
  2. 如果您有一个长期存在的页面,其中包含大量 javascript 交互,并且创建/销毁 DOM 对象的操作可以执行很多次。例如,无人值守运行的幻灯片可能一遍又一遍地创建/销毁 DOM 对象。即使每个项目的少量内存泄漏最终也会累积起来并导致问题。在我写的幻灯片中,我只是确保我没有在我添加/删除的这些特定 DOM 对象上放置任何自定义属性,并且在从 DOM 中删除对象之前删除了所有事件处理程序。这应确保不会对它们进行循环引用。
  3. 您在一个大循环中反复执行的任何类型的 DOM 操作。

关于javascript - 为什么这是 JavaScript 中的内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7519203/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com