5

(1) 我已经阅读了很多关于 IDisposable 的问题,其中的答案建议不要使用 Finalize,除非你真的需要,因为涉及的处理时间。
我没有看到的是这笔费用是多少以及支付的频率。每毫秒?第二?小时、天等

(2) 另外,在我看来,当它并不总是知道是否可以处置对象时,Finalize 很方便。例如,框架字体类。控件无法处理它,因为它不知道字体是否被共享。字体通常是在设计时创建的,因此用户不会知道如何处理它,因此 finalize 会在没有任何引用时最终摆脱它。这是正确的印象吗?

4

5 回答 5

8

finalize 的主要问题是它阻止了一个对象被垃圾收集。相反,会调用终结器,并在“下一次运行”时收集对象。好吧,从技术上讲,IIRC 终结器在单独的线程中运行对象列表。无论如何,这不是“每毫秒”的问题,更多的是“需要运行多次 GC 才能摆脱对象。

于 2010-06-15T13:57:28.783 回答
4

Finalize 在概念上与 Dispose 不同。Finalize只能释放非托管资源。Dispose 可以释放托管和非托管资源。您应该酌情使用每个。(请注意,具有终结器的类应始终实现 IDisposable)。

必须显式调用 Dispose;Finalize 只能由 GC 调用。

更新:请参阅我关于如何实施 IDisposable 和终结器的博客文章:3 条简单规则。

于 2010-06-15T14:00:32.357 回答
1

我会回答你的第二个问题。

不,Finalize不应该以这种方式使用。事实上,除了极少数的边缘情况外,如果类直接持有非托管资源,您应该只覆盖Finalize(或在 C# 中声明析构函数) 。

您描述的问题是所有权问题之一。类的所有者IDisposable负责其生命周期以及何时调用的决定Dispose。代码的其他部分可以免费使用该类,但由于它们不能声明所有权,因此不应参与该类的生命周期管理。

不幸的是,我不太熟悉这Font门课,也不熟悉它与引发您问题的特定场景的关系,但我可以做出一个可能适用于您的一般性陈述。如果您的代码没有直接创建实例(通过构造函数),那么您的代码不应被视为所有者。在这种情况下,您可以承担处理的责任留给其他人。

于 2010-06-15T16:24:41.537 回答
1

我有一篇关于 IDisposable 和 Finalizing 的博客文章——但不是关于性能的。

于 2010-06-15T14:06:38.603 回答
0

Finalize 作为双重检查非常有用。如果崩溃或某人的错误代码未在您的对象超出范围之前释放您的对象,请确保其资源将在终结器中释放。

你可以在你的处理器中做一些花哨的步法,但是通过调用GC.SuppressFinalize(this)which 将允许你编写一个在这两种情况下都可以工作的方法,并保证代码可以很好地工作。

如果您正在编写一个框架来提醒人们应该处置您的对象,您甚至可以触发 MDA。

终结器的惩罚基本上是您最终将对象推入需要更长运行时间的 2 级队列。如果您一直在使用对象并且它们正在终结,这可能会导致 2 级集合的运行频率高于运行终结器线程所需的频率。

于 2010-06-15T14:02:35.643 回答