请参见下面的代码。我希望它可以打印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;
}
}
[请注意,Main的类是由LINQPad(《 Cut 4.0 in a Nutshell》一书附带的编辑器)自动创建的。我是C#的新手。
您尚未运行显式垃圾回收。从GC.Collect()的文档中:
使用此方法尝试回收所有无法访问的内存。但是,Collect方法不确保所有不可访问的内存被回收。
所有对象,无论多长时间他们一直在记忆中,考虑收集;然而,托管中引用的对象代码未收集。用这个强制系统尝试的方法回收最大数量的可用内存。
垃圾收集器经过高度优化,当他实际进行垃圾收集然后调用终结器时,将由他自己“决定”。另外,所有这些都是异步完成的。这就是为什么将终结器称为非确定性清理的原因。当您进行清理时,您现在再也不会。
您现在有两个选择。您可以调用GC.WaitForPendingFinalizers(),这将暂停当前线程,直到所有可终结对象都已完成。或调用此新的重载:System.GC.Collect(int generation, System.GCCollectionMode mode)和GCCollectionMode.Forced
在.NET 3.5中引入。
请记住,通常没有必要,更重要的是:一个坏主意手动调用垃圾收集器。此外,仅在极少数情况下才需要实现终结器。调用垃圾收集器会减慢运行时间。实现终结器将另外减慢运行时间。当垃圾回收器准备好进行垃圾回收时,垃圾回收器会将实现该终结器的所有对象放入终结队列中。处理此队列非常昂贵。更糟糕的是,运行终结器时,不能保证您尝试访问的成员仍然存在。他们很有可能已经被劫持收集了。这就是为什么仅当您有需要清理的[[unmanaged资源时才应使用终结器的原因。在您的示例中,绝对不需要所有这些。您强烈想要的是IDisposable以进行确定性清除。
unmanaged
Dispose Pattern