【问题标题】:Does inline code keep the method [which wrote in it] in memory after finishing executing?内联代码在完成执行后是否将[其中写入的]方法保留在内存中?
【发布时间】:2010-06-18 23:40:44
【问题描述】:

据我所知,当我在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();
    }

【问题讨论】:

    标签: c# .net callback


    【解决方案1】:

    变量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 函数中实际使用的局部变量(因此,如果您的方法中有一些大数据,它们不会被意外保活比需要的时间长)。

    【讨论】:

      猜你喜欢
      • 2019-02-03
      • 2019-02-07
      • 2011-12-26
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      • 2011-07-20
      • 1970-01-01
      相关资源
      最近更新 更多