【问题标题】:what is relation between GC, Finalize() and Dispose?GC、Finalize() 和 Dispose 之间有什么关系?
【发布时间】:2022-01-18 00:35:51
【问题描述】:

GC 用于托管对象,而 Finalize 用于非托管对象,这就是我一直在阅读的内容。 Dispose 是隐式的, Finalize 是 Explicit 是我一直在阅读的内容。谁能给我一个模块的例子,其中三个东西都被用于不同的原因?

【问题讨论】:

  • 您不妨在使用时添加Using

标签: c# .net


【解决方案1】:

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 版刚刚发布。

【讨论】:

  • +1,但您可以补充一点,您可以使用 GC.SupressFinalize 抑制终结器,如果您明确处置实例,您会想要这样做。
  • 如果在对象符合清理条件时会自动调用 Finalize,那么为什么 C 不这样做呢?如果是自动过程?
  • 不会立即调用。它计划被调用。它可能需要一段时间才能运行。
  • @Californicated:您可以通过阅读我推荐的文章获得所有此类问题的答案
  • @EʜsᴀɴSᴀᴊᴊᴀᴅ 通常在未调用 Dispose 的情况下将终结器实现为后备。如果你这样做,记得从 Dispose 调用 GC.SupressFinalize。
【解决方案2】:

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

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

当对象即将被垃圾收集器收集时,会发生终结。这提供了一个“安全网”,如果比理想情况稍晚一点,仍然可以清理应该被处理的对象。通过实现终结器,您可以保证始终释放非托管资源。

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

【讨论】:

    【解决方案3】:

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

    这篇文章对这个主题几乎没有任何疑问。

    【讨论】:

    • 嗨,Mark,Dipose() 和其他两个之间的区别是我所理解的,但我正在努力理解 Finalize() 和 Garbage Collector() 之间的区别。因为我遇到了很多文章,作者说 GC 最终使用 Finalize() 来清除对象。那么在类定义中保留 Finalize() 和不保留一个有什么区别,因为即使我没有在类定义中保留 Finalize(),GC 最终也会调用 Finalize() 来清除未使用的对象。
    • 现在,在某处我读到带有 Finalize() 的对象将被放入“Finalization Queue”中,然后当不再需要该对象时,内存将被 GC 回收。
    • 事情看起来很复杂,因为 GC 是使用 Finalize() 而 Finalize 是使用 GC :)。我很困惑…………
    • 终结器只有在存在的情况下才会被调用,并且只有在你显式添加它的情况下才会存在。由于终结器使用资源,这就是为什么仅在您真正需要时才添加终结器很重要的原因。也就是说,您很少需要这样做 - 我已经编写 .NET 代码 8 年了,我不记得曾经编写过终结器,但我当然也远离与非托管代码的互操作。
    • 当一个实现终结器的类型的实例有资格被清理时,它会被放入终结队列中。此时它没有被清理,因为必须运行终结器。在某个时刻,终结器线程为实例执行终结器,之后该实例从队列中移除。在此之后,它不再被引用,因此将在下一次收集时被清理。
    猜你喜欢
    • 2017-12-03
    • 2011-04-08
    • 1970-01-01
    • 2013-10-30
    • 2015-01-02
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多