托管代码中块末尾的变量发生了什么

时间:2011-05-14 12:48:27

标签: c# .net memory-management object-lifetime

块结束后

{
}

块中的变量会发生什么变化?

{
    int a;
    a=2;
    int b = 3;
}

//What happened now???

以及此块后发生的事情

{
    int a=2;
    int b = 3;
}
GC.Collect();

清楚吗? 如果我选择的标签有误,请编辑它,或者如果您可以编辑我的问题,请编辑它。

3 个答案:

答案 0 :(得分:4)

块内的引用变量将超出范围。当被垃圾收集标记时,它们将保持标记,因为它们不再具有任何引用。由于您没有任何参考变量,因此GC不会参与。

在某一点上,垃圾收集器将运行并决定是否可以清除引用变量使用的内存。这取决于它们的生成,因此它们可能不会立即被删除。

调用GC.Collect();只会强制GC运行,但收集不确定。对于大多数应用来说,这不是必需的。

答案 1 :(得分:4)

在一个块结束时,所有变量都在'超出范围'内声明。

很可能它们会被堆叠掉,但细节可以通过优化器来实现。

由于您的示例变量都是int s(ValueTypes),因此它们与垃圾收集无关。

如果我们将最后一个示例更改为:

{
  int a=2;
  var b = new StringBuilder();
  ...
}
GC.Collect();

然后将在GC.Collect()中收集StringBuilder的内存。请注意,正常程序永远不需要调用GC.Collect()。

答案 2 :(得分:2)

在块结束时,块内声明的变量超出范围。如果它们是值类型(如int),它们只会从堆栈中弹出。如果它们是引用类型(像大多数其他对象,例如StringBuilder)那么它们将不再被引用(除非你将它传递给仍在范围内的块之外的东西),垃圾收集器将获取它过了一会儿。

如果你有对象访问稀缺资源,比如各种基于Stream的类(或任何实现IDisposable的类),那么你应该把它放在这样的using语句中:

using (Stream s = GetStream())
{
    // Do something with the stream.
}

在使用块结束时,调用Dispose方法并释放所有资源(例如文件处理程序,数据库连接,大块内存等)

通常,您无需了解垃圾收集器何时运行或释放内存。当我在2002年从C ++迁移到.NET时,这是我最难理解的事情之一,因为我习惯于在堆上创建的任何对象上调用delete

你不再需要担心这一点。即使您忘记调用dispose,垃圾收集器也会最终到达它(尽管您可能不希望保留该文件的句柄超过必要的时间,因此IDisposable

相关问题