堆上的结构如何解除分配?

时间:2016-03-09 12:22:58

标签: c# garbage-collection

当我在lambda中捕获int时,我猜它是在堆中分配的,以防止在块的末尾重新分配。 然后,它如何/何时被解除分配?值是否装箱(那么它必须像任何其他参考一样工作)? GC中是否有特殊功能来管理堆上的结构?

1 个答案:

答案 0 :(得分:2)

在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;
}

因此:

  

然后,如何/何时解除分配?

当类实例被释放时,它就像类实例的常规值类型字段一样被释放。

  

值是否已装箱(那么它必须像任何其他参考一样工作)?

通常,我们使用装箱来引用隐式表示 - 将值类型转换为特殊引用类型,其唯一的功能是(稍后)启用非表示更改的赋值引用类型位置的原始值(通常为object类型或实现原始值类型的任何接口类型)。在引擎盖下,拳击是由CLR使用a special IL instruction.

执行的

在lambda的上下文中,即使值可能作为类实例的字段进入堆,我们也不会将它称为常规意义上的装箱。在引擎盖下,通过为您编写一些等效的样板代码,捕获变量是C#编译器负责的事情。

当然,正如评论中所指出的那样,最终它们归结为同样的事情:它们在堆上分配一个结构。

  

GC中是否有特殊功能来管理堆上的结构?

具体而言,lambda捕获没有什么特别之处。 GC已经知道如何释放值类型字段。