【问题标题】:Why is this object not garbage collected? [duplicate]为什么这个对象没有被垃圾收集? [复制]
【发布时间】:2015-03-22 16:27:19
【问题描述】:

我仍然对 C# 的垃圾收集器感到有些困惑。文档指出,当没有更多引用指向该对象时,该对象将被垃圾回收。

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

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

【问题讨论】:

  • when there are no more references... 并不意味着只要没有更多的引用...
  • 当一个对象不再被引用时,它是有资格收集的。垃圾收集器仅在需要释放一些内存时运行,而不是在每次对象符合收集条件时立即运行。
  • 所以我的背景可能随时随机消失,因为我没有参考?我问这个是因为我真的从未见过这种情况发生。
  • 您的问题的答案完全取决于Background ctor 的作用。
  • “让我们假设背景类本身也没有创建引用。” -- 那么实例是否被垃圾回收有什么区别呢?几乎你的代码有意义的唯一方法是它是否确实创建了对自身的引用。

标签: c# garbage-collection


【解决方案1】:

您所描述的内容更类似于通过引用计数进行的内存管理,它检查在访问引用计数器时是否释放内存,通常是在构造或销毁引用对象时。

垃圾回收是一个稍微不同的概念。通常不允许或不建议在 GC 驱动的环境中直接释放对象。相反,偶尔会运行垃圾收集器(运行时决定何时执行此操作),它会找到所有不再引用的对象并释放这些对象占用的内存。关键是,您不应该打扰(因为您无能为力)何时会发生。

【讨论】:

  • 是的,但是在上面的例子中,我的背景是否有资格被垃圾收集,因此会从我的游戏中随机消失?我从未见过这种情况发生,尽管文档表明它可能会发生。
  • @Kokodoko 这不太可能。将执行时间分配给线程的调度程序应该知道正在运行的后台任务。只要一个线程存在,调度程序就会引用它并保持它完好无损。
  • 啊哈,只要后台类本身在执行代码就不会被垃圾回收?这说明了很多!
【解决方案2】:

垃圾收集器就像在您附近行驶的垃圾车。一旦你把垃圾放在路边,你就愿意捡起来。您必须等待它按自己的方式出现。

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

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

或者,如果您想保留您的对象,您需要保留对它的(间接)引用。该对象可能会在下一个垃圾回收周期中被回收。


嗯,有一个不推荐的方法来强制垃圾车收集你的垃圾,使用GC.Collect

GC.Collect();

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

【讨论】:

  • 谢谢!我知道你不能强迫垃圾车停在你家门口,但在上面的例子中,它会吗?我的后台类一直在我的游戏中愉快地运行,它根本没有被删除。
【解决方案3】:

C# 中的垃圾收集器仅在特定时刻被调用,并且是分代的。这意味着在第一次 GC 时没有引用的对象将被升级 1 代。最低一代比其他代更频繁地被垃圾收集。

你可以阅读这篇文章来了解更多:https://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

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

【讨论】:

  • 谢谢,但也许我的问题表述不够严格。我想知道是否需要保留参考以防止背景突然(随机)从我的游戏中消失。您是否会说在我上面的示例中,当 GC 决定它需要内存用于其他事情时,背景可能随时消失?
  • @Kokodoko - 这不是问题。您的背景不会显示(除非它的构造函数自己重新设置)。使用中 == 不受 GC 影响。
【解决方案4】:

如果您想检查一个对象是否会被垃圾回收,您可以通过以下操作在您的代码中测试它是否符合回收条件。

稍微修改您的方法以进行测试,或者您可以引用在 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");
}

这只是为了测试,否则你不应该调用垃圾收集器。

【讨论】:

  • 谢谢!我不知道你可以直接访问 GC。
猜你喜欢
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
  • 1970-01-01
  • 2010-11-10
  • 2011-06-14
相关资源
最近更新 更多