GC,Finalize()和Dispose之间的关系是什么?

时间:2010-02-26 19:25:19

标签: c# .net

GC用于托管对象,Finalize用于非托管对象,这是我一直在阅读的内容。 Dispose是隐式的,Finalize是Explicit是我一直在阅读的内容。有人可以给我一个模块的例子,其中所有三件事由于不同的原因被使用了吗?

3 个答案:

答案 0 :(得分:29)

GC是垃圾收集。它是自动内存管理,用于处理托管堆上分配的对象的清理。 .NET GC采用标记和扫描算法。当垃圾收集发生时,它基本上将要清理的堆部分中的所有对象都视为可恢复的。然后它会经历一个标记过程,在那里扫描根。即它标识应用程序仍在使用的对象。完成后,剩余的对象有资格进行清理。堆可以作为清理的一部分进行压缩。

Dispose和finalizer方法都提供了一个清理资源的选项,即由GC处理。例如。这可以是原生句柄等。它们与回收托管堆上的内存无关。

必须在实现IDisposable的类型上显式调用Dispose。可以通过Dispose()方法本身或通过using构造调用它。 GC不会自动调用Dispose。

另一方面,终结器或析构函数(如语言规范所称)将在对象符合清除条件后自动被称为 sometime 。 Finalize方法在专用线程上顺序执行。

Dispose()允许确定性清理资源,而终结者可以在用户不调用Dispose()时充当安全网。

如果类型实现了终结器,则实例的清理会被延迟,因为必须在清理之前调用终结器。即它将需要额外的收集来回收该类型实例的内存。如果类型也实现了IDisposable,则可以调用Dispose方法,然后实例可以从finalization中删除它自己。这将允许清理对象,就好像它没有终结器一样。

如果你想深入研究,我推荐CLR via C# by Jeffrey Richter。这是一本很棒的书,它涵盖了所有的血腥细节(我遗漏了一些细节)。新的第3版刚刚发布。

答案 1 :(得分:11)

.NET的一个好处是垃圾收集器。在许多语言中,每一块内存都必须由开发人员管理 - 任何分配的内存最终都应该被释放。在.NET(C#)中,垃圾收集器(GC)将负责为您释放内存的过程。它跟踪对象的使用情况,在它们变为“无根”之后(即:您的应用程序中没有直接或间接引用该对象的引用),对象的内存会自动清理。

Dispose,或更具体地说,IDisposable和Dispose模式用于独立于GC处理资源。由于各种原因,某些资源需要明确清理。这包括使用“本机”API(其中.NET不知道已分配的内存),使用包装本机句柄的资源等。为了清楚地处理这个问题,您实现了IDisposable和Dispose模式

当垃圾收集器即将收集对象时,会在对象上进行终结。这提供了一个“安全网”,如果比理想时间稍晚,那么应该已经处理过的物体仍然可以被清理干净。通过实现终结器,您可以保证始终释放非托管资源。

大多数示例的问题在于使用IDisposable有多种原因,并且正确的实现因您使用它的原因而异。例如,如果直接包装本机资源,则应该实现终结器,但如果封装另一个IDisposable类型,则不需要终结器,即使您仍应实现IDisposable。为了解决这个问题,我写了IDisposable and finalization in depth on my blog,描述了使用IDisposable的多种原因,以及出于不同原因的不同模式。

答案 2 :(得分:8)

您可能只想阅读我认为关于IDisposable,终结器和垃圾收集的权威文章,Shawn Farkas'CLR Inside Out: Digging into IDisposable

这篇文章对这个主题毫无疑问。