【发布时间】:2016-03-09 12:22:58
【问题描述】:
当我在 lambda 中捕获 int 时,我猜它是在堆中分配的,以防止在块末尾解除分配。
那么,如何/何时释放它?值是否被装箱(然后它必须像任何其他参考一样工作)? GC 中是否有特殊功能来管理堆上的结构?
【问题讨论】:
-
您捕获的变量成为隐藏类的字段。类对象的行为与其他对象一样。使用 ildasm.exe 亲自查看。
标签: c# garbage-collection
当我在 lambda 中捕获 int 时,我猜它是在堆中分配的,以防止在块末尾解除分配。
那么,如何/何时释放它?值是否被装箱(然后它必须像任何其他参考一样工作)? GC 中是否有特殊功能来管理堆上的结构?
【问题讨论】:
标签: c# garbage-collection
当在 lambda 中捕获局部变量时,it becomes a regular field in the compiler-generated lambda class。例如,这个:
static void Main(string[] args) {
int capture = 5;
Func<int, int> func = input => input * capture;
}
可以通过 C# 编译器降低为:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int capture;
internal int <Main>b__0(int input)
{
return input * this.capture;
}
}
private static void Main(string[] args)
{
new C.<>c__DisplayClass0_0().capture = 5;
}
因此:
那么,它是如何/何时释放的?
当类实例被释放时,它就像类实例的常规值类型字段一样被释放。
值是否被装箱(那么它必须像任何其他参考一样工作)?
一般来说,我们使用 boxing 来指代值类型到特殊引用类型的隐式表示更改转换,其唯一功能是(稍后)启用非表示更改分配引用类型位置的原始值(通常是 object 类型或原始值类型实现的任何接口类型)。在底层,装箱由 CLR 使用 a special IL instruction.
在 lambdas 的上下文中,即使值可能作为类实例的字段进入堆,我们也不将其称为常规意义上的装箱。在底层,捕获变量是 C# 编译器通过为您编写一些等效的样板代码来处理的事情。
当然,正如 cmets 中所指出的,最终它们都归结为同一件事:它们在堆上分配了一个结构。
GC 中是否有特殊功能来管理堆上的结构?
对于 lambda 捕获,没有什么特别的要求。 GC 已经知道如何释放值类型字段。
【讨论】: