垃圾收集和范围如何在C#中工作?

时间:2011-03-24 17:13:43

标签: c# .net python garbage-collection

我正在学习C#coming from python并想知道C#垃圾收集器是如何工作的 - 我发现一旦我弄清楚它在幕后做了什么,我就更了解python,并希望避免在学习python的时候,我首先做了一些菜鸟错误。

我无法找到任何关于物品何时被垃圾收集的明确解释,并留下诸如

之类的问题
  1. “当一个对象的最后一个引用超出范围时会发生什么?”该对象是否被垃圾收集,或者当您返回到定义它的范围时它是否仍然存在?
  2. “在什么时候推荐的数量会减少?”让我想知道它是否使用引用计数或其他技术......
  3. 对这些问题的回答,甚至更好地清楚地概述实际发生的事情将赢得cookie(或upvotes),如果你的答案将其与python的做事方式进行比较,那就更好了。我对哪个更好,只是细节不感兴趣。我对programmers.stackexchange上的原始帖子的答案也非常感谢......

5 个答案:

答案 0 :(得分:24)

dotnet GC引擎是一个标记和扫描引擎,而不是像你在python中习惯的引用计数器引擎。系统不维护对变量的引用计数,而是在需要回收RAM时标记所有当前可访问的指针并删除所有不可访问的指针(因此超出范围)。

您可以在此处找到有关其工作原理的更多信息:
http://msdn.microsoft.com/en-us/library/ee787088.aspx

系统通过从特定的“根”位置(如堆栈上的全局对象和对象)开始查找“可到达”对象,并跟踪这些对象引用的所有对象以及这些对象引用的所有对象,直到它构建为止一棵完整的树。这比听起来要快。

答案 1 :(得分:6)

在对象的最后一次引用消失后的某个不确定的时间点,将收集该对象。

第一个问题的第二部分没有意义 如果你可以回到定义对象的范围(例如,lambda表达式),显然仍然有一个引用。

GC根本不使用引用计数 相反,它使用mark-and-sweep algorithm

答案 2 :(得分:5)

引用超出范围不会触发垃圾收集。通常在为新对象分配存储时触发垃圾收集 - 特别是在生成零预算用尽时。即在对象符合垃圾收集条件和实际收集垃圾的时间之间可能存在显着延迟。正如其他人已经指出的那样,CLR不使用引用计数。相反,它采用了标记和扫描方法。

关于垃圾收集如何运作的所有细节的一个很好的信息来源是Jeffrey Ricther的书CLR via C#。本书详细介绍了堆如何分区以及垃圾收集的工作原理。如果您对.NET实现细节感兴趣,强烈建议使用。

答案 3 :(得分:3)

  1. 当一个对象不再具有强引用时,不会立即发生任何事情。为每个对象分配一代,0,1或2.最初,所有对象都放在0代中。使用Mark-and-Sweep算法,垃圾收集器将定期检查生成。如果实例仍然具有任何强引用,则会将其提升为最高为2的较高代(通常检查频率较低)。这背后的理论是,大多数对象通常都是短暂的,所以如果一个对象的寿命足够长到第1代,那么就不需要经常检查它。
  2. .NET GC中没有引用计数。相反,它使用标记和扫描。

答案 4 :(得分:0)

'垃圾收集'由垃圾收集器执行,垃圾收集器是.NET框架中CLR的一部分。

它是一个通过识别不再需要的对象来释放内存的自动过程,不像c,c ++,程序员明确地必须释放内存。

垃圾收集器如何工作

它会定期查看内存,即托管堆,并释放死对象占用的内存。

如果您的代码无法访问死对象,则会识别死对象。

实施

有三种方法可以实现内存管理: -

GC仅适用于托管资源,因此.NET提供Dispose和Finalize来释放非托管资源,如流,数据库连接,COM对象等。

1)处理

必须为实现IDisposable的类型显式调用Dispose。

程序员必须使用Dispose()或使用construct

来调用它

如果您已使用dispose()

,请使用GC.SuppressFinalize(this)来阻止调用Finalizer

2)Finalize或Distructor

在对象符合清理条件后隐式调用它,对象的终结器由终结器线程按顺序调用。

实现终结器的缺点是内存回收被延迟,因为必须在清理之前调用此类/类型的终结器,因此需要额外的回收来回收内存。

3)GC.Collect()

使用GC.Collect()并不一定要将GC用于收集,GC仍可以随时覆盖并运行。

GC.Collect()也只会运行垃圾收集的跟踪部分,并将项目添加到终结器队列,但不会为其他线程处理的类型调用终结器。

如果要确保在调用GC.Collect()之后调用所有终结器,请使用WaitForPendingFinalizers

请参阅我的博客上的帖子,我有这篇文章: - Garbage collection in .NET