Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/469.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么这是JavaScript中的内存泄漏?_Javascript_Memory Management_Memory Leaks - Fatal编程技术网

为什么这是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

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

编写(“通过闭包说明内存泄漏的程序”);
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>
实际上,这只是在少数情况下的一个有意义的问题,因为泄漏的内存使用量可能非常大

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

  • 这是由于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>