【发布时间】:2022-01-18 00:35:51
【问题描述】:
GC 用于托管对象,而 Finalize 用于非托管对象,这就是我一直在阅读的内容。 Dispose 是隐式的, Finalize 是 Explicit 是我一直在阅读的内容。谁能给我一个模块的例子,其中三个东西都被用于不同的原因?
【问题讨论】:
-
您不妨在使用时添加
Using。
GC 用于托管对象,而 Finalize 用于非托管对象,这就是我一直在阅读的内容。 Dispose 是隐式的, Finalize 是 Explicit 是我一直在阅读的内容。谁能给我一个模块的例子,其中三个东西都被用于不同的原因?
【问题讨论】:
Using。
GC 是垃圾回收。它是自动内存管理,处理托管堆上分配的对象的清理。 .NET GC 采用标记和扫描算法。当垃圾收集发生时,它基本上认为要清理的堆部分中的所有对象都是可恢复的。然后它会通过一个标记过程来扫描根。 IE。它标识应用程序仍在使用的对象。完成后,剩余的对象就有资格进行清理。作为清理的一部分,可以压缩堆。
Dispose 和 finalizer 方法都提供了清理资源的选项,这些资源不由 GC 处理。例如。这可能是本机句柄等。它们与回收托管堆上的内存无关。
必须在实现IDisposable 的类型上显式调用Dispose。可以通过Dispose() 方法本身或using 构造调用它。 GC 不会自动调用 Dispose。
另一方面,终结器或析构器(如语言规范所称)将在对象符合清理条件后自动调用某个时间。 Finalize 方法在专用线程上按顺序执行。
Dispose() 允许确定性地清理资源,而终结器可以充当安全网,以防用户不调用Dispose()。
如果一个类型实现了终结器,实例的清理会延迟,因为终结器必须在清理之前调用。 IE。它将需要额外的收集来回收该类型实例的内存。如果该类型也实现了 IDisposable,则可以调用 Dispose 方法,然后实例可以将自身从终结中移除。这将允许清理对象,就好像它没有终结器一样。
如果你想深入研究这个,我推荐CLR via C# by Jeffrey Richter。这是一本很棒的书,它涵盖了所有血腥的细节(我遗漏了一些细节)。新的第 3 版刚刚发布。
【讨论】:
.NET 的好处之一是垃圾收集器。在许多语言中,每一块内存都必须由开发人员管理——任何分配的内存最终都应该被释放。在 .NET (C#) 中,垃圾收集器 (GC) 将负责为您释放内存的过程。它会跟踪您的对象的使用情况,并在它们“无根”后(即:您的应用程序中没有直接或间接地对该对象的引用),该对象的内存会被自动清理。
Dispose,或者更具体地说,IDisposable 和 Dispose 模式用于与 GC 分开处理资源。由于各种原因,某些资源需要显式清理。这包括使用“本机”API(其中 .NET 不知道分配的内存),使用包装本机句柄的资源等。为了干净地处理这个,您实现 IDisposable 和 Dispose 模式。
当对象即将被垃圾收集器收集时,会发生终结。这提供了一个“安全网”,如果比理想情况稍晚一点,仍然可以清理应该被处理的对象。通过实现终结器,您可以保证始终释放非托管资源。
大多数示例的问题在于使用 IDisposable 的原因有多种,而正确的实现方式会因您使用它的原因而异。例如,如果直接包装本机资源,则应实现终结器,但如果封装另一个 IDisposable 类型,则不需要终结器,即使您仍应实现 IDisposable。为了解决这个问题,我写了一篇关于 IDisposable and finalization in depth on my blog 的文章,描述了您使用 IDisposable 的多种原因,以及出于不同原因的不同模式。
【讨论】:
您可能只想阅读我认为关于 IDisposable、终结器和垃圾收集的权威文章,Shawn Farkas 的CLR Inside Out: Digging into IDisposable。
这篇文章对这个主题几乎没有任何疑问。
【讨论】: