Man*_*noj 5 c# garbage-collection destructor
请参阅下面的代码.我希望它打印10,因为我已经显式调用了垃圾收集器.但我总是输出0或20作为输出.这是为什么?
void Main()
{
Panda[] forest_panda = new Panda[10];
for(int i=0; i<forest_panda.GetLength(0);i++)
{
forest_panda[i]=new Panda("P1");
}
for(int i=0; i<forest_panda.GetLength(0);i++)
{
forest_panda[i]=new Panda("P1");
}
System.GC.Collect();
Console.WriteLine("Total Pandas created is {0}",Panda.population);
}
class Panda
{
public static int population=0;
public string name;
public Panda(string name)
{
this.name = name;
population = population + 1;
}
~Panda()
{
population = population - 1;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,Main的类是由LINQPad("Nutshell中的C#4.0"一书中的编辑器)自动创建的.我是C#的新手.
您尚未运行explict垃圾回收.来自GC.Collect()的文档:
使用此方法尝试回收所有无法访问的内存.但是,Collect方法不保证回收所有无法访问的内存.
所有对象,无论它们在记忆中存在多长时间,都被考虑收集; 但是,不会收集托管代码中引用的对象.使用此方法强制系统尝试回收最大可用内存量.
garabage收集器是高度优化的,当他实际进行垃圾收集然后调用终结器时,他自己"决定"所有.此外,它都是异步完成的.这也是Finalizer被称为非确定性清理的原因.你现在从未做过清理工作.
你现在有两个选择.您可以调用GC.WaitForPendingFinalizers(),它将暂停当前线程,直到完成所有可终结对象.或者调用这个新的重载:System.GC.Collect(int generation,System.GCCollectionMode mode) with GCCollectionMode.Forced.NET是在.NET 3.5中引入的.
请记住,通常没有必要,更重要的是:手动调用垃圾收集器是个坏主意.只有在极少数情况下才需要实现终结器.调用垃圾收集器会降低运行时间.实现终结器还会减慢运行时间.当准备好收集garabge时,garabge收集器将实现终结器的所有对象放入终结队列.处理此队列非常昂贵.更糟糕的是,当终结器运行时,无法保证您尝试访问的成员仍然存在.他们很可能已经收集了垃圾.这就是为什么你应该只在你没有管理时才使用终结器 需要清理的资源.
在您的示例中,绝对不需要所有这些.你真正想要的是IDisposable用于确定性清理.
这里有几点需要注意:
首先,GC在发布和调试版本之间表现不同.通常,在释放模式下,可以比在调试模式下更快地回收对象.
正如Tim所说,调用GC.Collect不会调用终结器.如果你想等终结器运行,也可以调用GC.WaitForPendingFinalizers.
终结器由专用线程运行,因此您实际上是在没有任何同步的情况下从两个不同的线程修改状态.虽然在这种特殊情况下这可能不是问题,但这样做并不是一个好主意.但是在你去为终结器添加同步之前,请记住,死锁的终结器意味着不再运行终结器,因此这些对象的内存将不会被回收.