【问题标题】:Understanding javascript closures and memory usage了解 javascript 闭包和内存使用
【发布时间】:2011-06-01 16:26:39
【问题描述】:

编辑:这只是一个简单的例子来证明我对一个更大的程序的担忧。我不会将这个实际代码用于任何事情:)

如果我运行这个 -

<!DOCTYPE html>
<html>
<head>
<script>

function update(amount, win, data)
{
    win.innerText = 'Count is ' + amount;
    setTimeout(function() { update(amount + 1, win, {data: 'something'})}, 1000);
}

window.onload = function() {

  var win = document.getElementById('item');    
  update(0, win, 0);
}
</script>
</head>

<body>
<div id="item"></div>
</body>
</html>

对 setTimeout 的调用可能会创建一个闭包,该闭包将参数的内容捕获到“更新”函数(数量、获胜、数据)。因此,这些变量会一直保存在内存中,直到调用超时并返回,以便它们在该函数调用中可用...

但是该函数为超时的下一次迭代创建了一个 new 闭包......在第二个闭包中将捕获什么?仅仅是这些变量的副本还是会在新闭包中再次捕获构成函数调用一部分的那些?

基本上这最终会因为每个闭包中的数据越来越大而耗尽内存,还是这样安全合理?

【问题讨论】:

标签: javascript closures


【解决方案1】:

在我的理解中,当一个闭包被创建时,当前的词法上下文是和它捆绑在一起的。在您的情况下,它将是amount, win, data

当超时触发时,这个上下文将被用来执行闭包,从而再次调用函数update;这个调用虽然看起来是这样,但它不是递归的,因为之前的update 的执行已经结束,并且它的原始上下文(动态的,不同于词法的)已经被释放了。 (我认为这很重要,因为您似乎担心由于递归而导致的堆栈增长)。

因此,update 再次执行第二次,并再次设置超时并创建闭包。这个闭包与当前执行的词法上下文捆绑在一起(仍然只包括amount, win, data),并与计时器一起调度。然后update 完成并从堆栈中删除。然后再次触发计时器并再次调用更新...

因此,您不必担心上下文的无限增长,原因有两个:首先,只有词法上下文与闭包捆绑在一起;该调用实际上不是递归的。

【讨论】:

  • "只有词汇上下文与闭包绑定" 我想这是我想问的问题 :) - 这不是我担心的堆栈增长,我知道它不是递归的 - 它是对数据的无限“捕获”。
【解决方案2】:

正如你所说的,每次调用超时回调时都会创建一个新的闭包。但是一旦回调被执行,不再有任何引用之前的闭包,所以它可以被垃圾回收。

【讨论】:

  • 我关心的不是第一个闭包被垃圾收集,而是通过闭包传递给回调的参数中的数据......它们在创建第二个闭包时可用,所以如果他们在 second 闭包中被捕获,那么它们将不会被释放。但我不确定它们是否会被捕获,或者它是否只是在第二个函数中直接声明的变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 2013-01-18
  • 1970-01-01
  • 2012-04-04
  • 2013-01-11
  • 2018-02-17
  • 2019-08-20
相关资源
最近更新 更多