在完成执行后,内联代码是否将[在其中写入的方法]保留在内存中?

时间:2010-06-18 23:40:45

标签: c# .net callback

根据我所知,当我在C#中定义一个方法时,在完成执行此方法的块[当GC想要]时,此方法中的局部变量将从内存中释放,

但如果我在方法中有内联回调,这些局部变量是否也会从内存中释放出来?

在下面的例子中,[x]变量将在完成执行方法后保持其值,并且消息将显示[x]的值而没有问题,尽管它在回调中!!

    private void MyMethod()
    {
        int x = 1;
        System.Timers.Timer t = new System.Timers.Timer(1000);
        t.Elapsed += (sender, e) => MessageBox.Show((x++).ToString()); ;
        t.Start();
    }

1 个答案:

答案 0 :(得分:5)

变量x在与lambda函数关联的闭包中捕获。这意味着x的值实际上并不存储在与MyMethod的执行相关联的堆栈上,而是存储在堆上(在从lambda函数引用的对象中)。

以下示例(粗略地)显示了C#编译器如何转换代码:

class $$MyMethod$$Closure { 
  public int x;
  void Function(object sender, EventArgs e) {
    MessageBox.Show((x++).ToString());
  }
}

private void MyMethod() {
    var $$closure = new $$MyMethod$$Closure();
    $$closure.x = 1; 
    System.Timers.Timer t = new System.Timers.Timer(1000); 
    t.Elapsed += $$closure.LambdaFunction; 
    t.Start(); 
}

如您所见,x变量现在存储在堆分配的对象(称为闭包)中。只要计时器可以调用该方法(并且只要x可以访问),该对象就会处于活动状态,但是一旦删除了计时器,关闭也将被垃圾收集。

值得注意的是,编译器只捕获 lambda函数中实际使用的那些局部变量(所以如果你在方法中有一些大数据,它们就不会被意外保存比需要的时间长。)