在创建闭包时(在Javascript或C#中),闭包创建时范围内的所有变量是否都“封闭”在其中?或者只是新创建的方法中引用的变量?
示例C#代码:
private void Main() {
var referenced = 1;
var notReferenced = 2; // Will this be enclosed?
new int[1].Select(x => referenced);
}
示例Javascript代码:
var referenced = 1;
var notReferenced = 2; // Will this be enclosed?
var func = function () {
alert(referenced);
}
(通过使用Javascript闭包创建循环引用来阅读IE中的内存泄漏时,问题来了。http://jibbering.com/faq/notes/closures/#clMem)
注意:使用“封闭”一词,我的意思是MSDN称之为“已捕获”。 (http://msdn.microsoft.com/en-us/library/bb397687.aspx)
答案 0 :(得分:18)
答案 1 :(得分:8)
这里有两个问题。将来,如果您有两个问题,可以考虑发布两个单独的问题。
在C#中创建闭包时,闭包创建时范围内的所有变量是否都“包含”在其中?或者只是新创建的方法中引用的变量?
这取决于您是否要求 dejure 或事实答案。
首先,让我们澄清你的问题。我们将“外部变量”定义为局部变量,值参数(即,不是ref或out),“params”参数,或者在方法内部但在任何lambda或匿名方法之外发生的实例方法的“this”该方法中的表达式。 (是的,“这个”被归类为“外部变量”,即使它没有被归类为“变量”。这很不幸,但我已经学会了忍受它。)
在lambda或匿名方法表达式中使用的外部变量称为“捕获的外部变量”。
现在让我们重新提出问题:
在运行时创建与lambda或匿名方法对应的委托时, all 的生命周期是在委托创建时扩展到匹配(或超过)范围内的外部变量)代表的生命周期?或者只是捕获的外部变量的生命周期?
事实上,只延长了捕获的外部变量的生命周期。 De jure ,规范要求捕获的外部变量的生命周期被扩展,但禁止未捕获的外部变量的生命周期延长
阅读C#4规范的5.1.7,6.5.1和7.15.5节,了解所有细节。
Jon指出,我们并没有特别好地确保捕获的外部变量的生命周期最小化。我们希望有一天会做得更好。
答案 2 :(得分:5)
我只能在C#方面回答。
如果闭包实际上没有捕获变量,它将作为方法中的常规局部变量保留。如果它被捕获,它将仅被提升为合成类中的实例变量。 (当我谈到变量被“封闭”时,我假设你正在谈论这个。)
但是,请注意,如果两个lambda表达式各自捕获相同作用域的不同变量,那么在当前实现中两个 lambdas将使用相同的合成类:
private Action Foo() {
var expensive = ...;
var cheap = ...;
Action temp = () => Console.WriteLine(expensive);
return () => Console.WriteLine(cheap);
}
此处返回操作仍然会使“昂贵”引用保持活动状态。所有这些都是Microsoft C#4编译器的实现细节,但将来可能会发生变化。
答案 3 :(得分:3)
我只能回答有关C#:
的问题不,它不会被封闭,因为它不需要。
我解释“它会被封闭吗?”在这种情况下,如下所示:
是否会在为lambda表达式生成的闭包内捕获它,即自动生成的类中是否有一个包含此变量值的字段?
声明:
这是一个实现细节。我的答案适用于MS针对您的特定情况当前实现的C#编译器。它可能与Mono编译器或更新版本的MS编译器不同。或者 - 正如Jon的回答所示 - 对于一个更复杂的例子,它可能会有所不同。
答案 4 :(得分:1)
在创建闭包时(在Javascript或C#中),闭包创建时范围内的所有变量是否都“封闭”在其中?或者只是新创建的方法中引用的变量?
我只能回答有关JavaScript的问题。
这是特定于实现的。一些引擎包含所有变量。一些引擎优化并且只包含引用的变量。
我知道Chrome会优化并且只包含它关心的变量。
进一步阅读:
似乎这个问题源于对旧的IE内存泄漏问题的担忧。这在现代浏览器中不是问题。
通过在EcmaScript和Host对象之间进行循环引用,很好地了解了IE8中仍然存在的内存泄漏:
为了澄清有关闭包的IE内存泄漏问题,它主要是关于Host对象(DOM)和JavaScript之间的循环引用。因此,除非您使用DOM(el.attachEvent
或类似的东西)