为什么这个对象不是垃圾收集的?

时间:2015-03-22 16:27:20

标签: c# garbage-collection

我仍然对C#的垃圾收集器感到困惑。文档说明当没有更多引用指向它时,对象是垃圾收集。

所以我的问题是,为什么这个对象不会立即被垃圾收集?没有提到它。我们假设背景类本身也没有创建引用。

public void StartGame() {
   // the background instance is created, but no reference is kept:
   new Background("landscape.png", speed);
}

4 个答案:

答案 0 :(得分:2)

您所描述的内容与内存管理更相似,通过引用计数来检查是否在访问引用计数器时释放内存,通常是在构造或销毁引用对象时。 / p>

垃圾收集是一个略有不同的概念。通常不允许或不建议直接释放GC供电环境中的对象。相反,垃圾收集器偶尔运行(运行时决定何时执行),查找所有不再引用的对象并释放这些对象占用的内存。关键是,你不应该打扰(因为你什么都不做),确切的时候会发生。

答案 1 :(得分:2)

垃圾收集器就像是在你附近开车的垃圾车。一旦把它放在街道的一边,你就不能将它拿起你的垃圾。你必须等待它自己的条件。

垃圾收集器在理论上非常简单:停止世界,确定不再使用的东西,收集,恢复世界。但是因为这需要时间,开发人员使用复杂的算法来确定收集器何时启动以及收集什么,以使程序尽可能顺利地运行。一些垃圾通常不会影响您的程序。

如果您希望在对象超出范围时立即收集对象,并且您可能正在使用终结器来测试它。别!相反,实施IDisposable并在完成后立即自行调用Dispose方法。如果有的话,你不能随时依赖垃圾收集器来收集你的对象。这就是为什么BCL I / O类都实现IDisposable来刷新流,关闭连接和清理内存。

或者如果你想保持你的对象,你需要来保持(间接)引用它。该对象可能只是在下一个垃圾收集周期中收集。


嗯,有一种不推荐的方式强制垃圾车收集垃圾,使用GC.Collect

GC.Collect();

这会暂时阻止你的程序收集所有垃圾。但是,当它存在于堆栈或其他位置时,这可能仍然无法清除您的Background对象。您无法预测运行时将放置对象的位置以及何时将其释放,因此请确保在测试是否使用GC.Collect收集对象之前至少退出创建对象的方法。

答案 2 :(得分:1)

C#中的垃圾收集器仅在某些时刻被调用并且是世代的。这意味着在GC的第一次通过时没有引用的对象将升级1代。最低代的垃圾收集方式比其他方式更频繁。

您可以阅读本文以了解更多信息:https://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

您也可以调用GC.Collect方法,但不建议这样做,因为.NET几乎能够处理自己的内存并且调用此方法有点挫败了整个目的。

答案 3 :(得分:1)

好吧,如果你想检查一个对象是否会被垃圾收集,你可以通过执行以下操作,在你的代码中测试它是否符合收集标准。

稍微修改你的方法以进行测试,或者你可以引用一个在StartGame方法中设置的字段。

public void StartGame(out WeakReference reference)
{
    reference = new WeakReference(new Background("landscape.png", speed));
}

调用方法后,您可以执行以下操作以查看它是否符合收集条件。

WeakReference reference;
StartGame(out reference);
GC.Collect();
GC.WaitForPendingFinalizers();
if (reference.IsAlive)
{
    Console.WriteLine("Background is not eligible for collection");
}

这仅用于测试,否则你不应该调用垃圾收集器。