【问题标题】:How is a struct on the heap deallocated?如何释放堆上的结构?
【发布时间】:2016-03-09 12:22:58
【问题描述】:

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

【问题讨论】:

  • 您捕获的变量成为隐藏类的字段。类对象的行为与其他对象一样。使用 ildasm.exe 亲自查看。

标签: c# garbage-collection


【解决方案1】:

当在 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 已经知道如何释放值类型字段。

【讨论】:

  • @HenkHolterman ????仅以最一般的方式...现在您有一个包含值类型的引用类型而不是值类型...但是如果您有多个值类型,隐藏的引用类型仍然是一个。
  • @HenkHolterman 我不同意你的观点——事实上,我在写这个答案时就想到了它。但我更愿意避免重新定义特定技术的易于理解的术语。在 C# 中,他们使用“装箱”来表示将值类型自动包装为实现值类型接口的 专用 引用类型 - 他们不(传统上)使用“装箱结构”来引用任何堆分配结构。
  • @TheodorosChatzigiannakis 感谢您的完整回答
  • @HenkHolterman 和 Theodoros Chatzigiannakis 感谢您的 cmets。我会问它与拳击有什么不同。现在我知道了。
猜你喜欢
  • 1970-01-01
  • 2010-09-30
  • 1970-01-01
  • 2017-03-09
  • 1970-01-01
  • 2012-02-20
  • 1970-01-01
  • 2016-04-13
  • 1970-01-01
相关资源
最近更新 更多