17

我知道最好的做法是在任何实现 IDisposable 的对象上调用 Dispose,尤其是包装有限资源(如文件句柄、套接字、GDI 句柄等)的对象。

但是我遇到了一个情况,我有一个有字体的对象,我必须通过几层对象来探测 IDisposable,并查看很多用法,以确保我总是处理字体。我想知道它是否值得复杂。

如果 Font 包装了 HFONT,那将是一回事,因为 GDI 资源是系统全局的。但是 Font 不包装 GDI 句柄;它是 GDI+,它是一个完全独立的系统,据我所知,它是本地进程,而不是像 GDI 那样的系统全局。与 Image 不同,Font 永远不会占用文件系统资源(无论如何我都知道)。

所以我的问题是:让字体收集垃圾的真正成本是多少?

我知道我会对终结者造成一点打击,但如果“泄漏”字体的数量很少(比如六个),那么老实说,这种打击不会引起注意。除了终结器之外,这似乎与分配一个中等大小的数组并让 GC 清理它没有太大区别——它只是内存。

让字体获得 GCed 是否有我不知道的成本?

4

6 回答 6

5

问题是垃圾收集仅在内存压力存在时发生。通常,非托管句柄比内存更受限制,因此您可能会在 GC 发生之前用完句柄,从而导致错误。

但是对于一两个Font实例,它不会过度伤害你。

一个更大的问题是一些对象是共享的,不应该(或不能)过早地处置......

于 2009-04-15T15:57:05.173 回答
5

简单的回答:如果只是几个,那么没有。如果它很多,那么是的。如果您的应用程序已经对垃圾收集器施加压力,那么可以。我会使用 perfmon 查看周围的对象数量,以及提升到更高代的数量,然后再决定。

于 2009-04-15T15:58:00.833 回答
5

为什么不做完就扔掉?仅仅因为我们有清道夫,并不意味着我们应该到处乱扔垃圾。但是,在给出的示例中,如果对象的生命周期需要字体,则在该对象的 dispose 中处置该字体。有很多事情也可以简化我的代码,但这并不能证明这些更改是合理的——有时有些事情你应该做,即使这很痛苦。

自己收拾东西总是一个好主意。当您不再需要某物时,请丢弃它。这样,您就可以避免令人讨厌的竞争条件、内存不足异常、绘图故障以及冗长的处理器密集型垃圾收集。

我发现如果您不再需要一次性物品,最好将其丢弃,除非有正当理由不这样做(例如您不拥有该物品)。追查问题的根本原因比预先编写防御性代码更难。

关于字体,MSDN 说

在发布对字体的最后引用之前,请始终调用 Dispose。否则,在垃圾收集器调用 Font 对象的 Finalize 方法之前,它正在使用的资源不会被释放。

它没有说明资源是什么,但它们明确声明应该隐含地完成这一事实增加了调用 Dispose 的重要性。

于 2009-04-15T16:52:58.843 回答
3

处理任何东西有多重要,真的吗?恕我直言,当您开始提出此类问题时,听起来您的代码中存在设计问题。你应该总是处理你不再需要的东西——这叫做负责任的编程。

您的问题的可能解决方案:

  • 请勿传递诸如Fonts. 在一个地方(一个类)实现字体使用逻辑,将字体添加为该类的字段并IDisposable为该类实现。

  • 实现一个字体缓存类——而不是在整个代码中使用运算符创建新Font对象,而是new使用这个类来获得所需的Font. 如果可能,该类可以具有重用现有字体的逻辑。或者将最后 10 种字体保留在内存中,并丢弃其他字体。为缓存实现IDisposable,它将在您的应用程序的生命周期中调用一次。

于 2009-04-16T18:24:23.730 回答
1

终结器专门内置在类中,因为清理是必要的。无论您有大量或少量的对象要清理,清理它们都是一个好习惯。

GC 是为了拥有自己的伪思维而构建的。通过正确处理你的对象,你允许 GC 做它应该做的事情。

但是,如果您正在创建大量字体对象并处理所有字体对象,则每隔一段时间在适当的代(可能是第 0 代)调用 GC 以根据类型自行启动 GC 清理可能是有益的您正在大量实例化的其他对象。您的目标应该是让您知道您不会使用很长时间的物品不会被提升为老一代。这使 GC 的工作保持精简和平均。

只要用你最好的判断,你会没事的。但是,作为您的正常做法,确实要使用终结器处理任何对象。

于 2009-04-15T17:23:08.663 回答
-2

我至少运行了一个使用 .NET 运行时的其他应用程序。我不断收到 OutOfMemoryExceptions。最好让您的应用程序正常运行,以便其他应用程序在无法获得足够资源时不会抛出异常。

于 2013-02-20T00:11:46.243 回答