根据我所知,当我在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();
}
Run Code Online (Sandbox Code Playgroud)
该变量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();
}
Run Code Online (Sandbox Code Playgroud)
如您所见,x变量现在存储在堆分配的对象(称为闭包)中.只要定时器可以调用该方法(并且只要x可以访问),该对象将是活动的,但是一旦移除了定时器,闭包也将被垃圾收集.
值得注意的是,编译器只捕获 lambda函数中实际使用的那些局部变量(因此,如果方法中有一些大数据,它们不会意外地保持活动时间超过需要).