我正在学习C#coming from python并想知道C#垃圾收集器是如何工作的 - 我发现一旦我弄清楚它在幕后做了什么,我就更了解python,并希望避免在学习python的时候,我首先做了一些菜鸟错误。
我无法找到任何关于物品何时被垃圾收集的明确解释,并留下诸如
之类的问题对这些问题的回答,甚至更好地清楚地概述实际发生的事情将赢得cookie(或upvotes),如果你的答案将其与python的做事方式进行比较,那就更好了。我对哪个更好,只是细节不感兴趣。我对programmers.stackexchange上的原始帖子的答案也非常感谢......
答案 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)
答案 4 :(得分:0)
'垃圾收集'由垃圾收集器执行,垃圾收集器是.NET框架中CLR的一部分。
它是一个通过识别不再需要的对象来释放内存的自动过程,不像c,c ++,程序员明确地必须释放内存。
它会定期查看内存,即托管堆,并释放死对象占用的内存。
如果您的代码无法访问死对象,则会识别死对象。
有三种方法可以实现内存管理: -
GC仅适用于托管资源,因此.NET提供Dispose和Finalize来释放非托管资源,如流,数据库连接,COM对象等。
必须为实现IDisposable的类型显式调用Dispose。
程序员必须使用Dispose()或使用construct
来调用它如果您已使用dispose()
,请使用GC.SuppressFinalize(this)来阻止调用Finalizer在对象符合清理条件后隐式调用它,对象的终结器由终结器线程按顺序调用。
实现终结器的缺点是内存回收被延迟,因为必须在清理之前调用此类/类型的终结器,因此需要额外的回收来回收内存。
使用GC.Collect()并不一定要将GC用于收集,GC仍可以随时覆盖并运行。
GC.Collect()也只会运行垃圾收集的跟踪部分,并将项目添加到终结器队列,但不会为其他线程处理的类型调用终结器。
如果要确保在调用GC.Collect()之后调用所有终结器,请使用WaitForPendingFinalizers
请参阅我的博客上的帖子,我有这篇文章: - Garbage collection in .NET