我知道最好的做法是在任何实现IDisposable的对象上调用Dispose,尤其是包装有限资源的对象,如文件句柄,套接字,GDI句柄等。
但我遇到的情况是我有一个带有Font的对象,我必须通过几层对象检测IDisposable,并查看很多用法,以确保我总是得到Font处理。而且我想知道它是否值得复杂。
如果Font包装了一个HFONT,那将是一回事,因为GDI资源是系统全局的。但是Font没有包装GDI句柄;它是GDI +,它是一个完全独立的系统,据我所知,它是流程本地的,而不是像GDI那样的系统全局。与Image不同,Font不会保留文件系统资源(我知道,无论如何)。
所以我的问题是:让Font收集垃圾的实际成本是多少?
我知道我会在终结器上受到轻微的打击,但如果“泄露”字体的数量很小(比如说有六个),那么这个命中率就不会引人注意。除了终结器之外,这与分配中型阵列并让GC清理它似乎没什么不同 - 它只是内存。
在让Font得到GCed时,我不知道有什么费用吗?
答案 0 :(得分:5)
简单回答:如果它只是几个,那么没有。如果它很多,那么是的。如果您的应用程序已经在强调垃圾收集器,那么是的。我会使用perfmon来查看坐在周围的对象的数量,并将数字提升到更高代,然后再决定。
答案 1 :(得分:4)
问题是垃圾收集只在有内存压力时才会发生。通常,非托管句柄比内存更受限制,因此在GC发生之前可能会用尽句柄,从而导致错误。
但是对于一个或两个Font
个实例,它不会过度伤害你。
更大的问题是某些对象是共享的,不应该(或不能)过早地处理......
答案 2 :(得分:4)
为什么一旦完成就不会处理掉它?仅仅因为我们有清道夫并不意味着我们应该四处乱逛街头。但是,在给出的示例中,如果对象的生命周期需要字体,则在该对象的dispose中处理该字体。有很多东西可以简化我的代码,但这并不能证明这些变化是正确的 - 有时候你应该做些什么,即使这很痛苦。
自己整理后总是一个好主意。当您不再需要某些东西时,请将其丢弃。这样你就可以避免令人讨厌的竞争条件,内存异常,绘制故障以及冗长的处理器密集型垃圾收集。
我发现如果您不再需要它们,最好先处理一次性物品,除非有合理的理由不这样做(例如您没有拥有该物体)。追踪问题的根本原因比预先编写防御性代码要困难得多。
关于Font,MSDN says:
在释放对Font的最后一个引用之前,请始终调用Dispose。否则,在垃圾收集器调用Font对象的Finalize方法之前,不会释放它正在使用的资源。
它没有说明资源是什么,而是它们明确声明这应该隐式完成的事实增加了调用Dispose的重要性。
答案 3 :(得分:3)
处理任何事情有多重要?恕我直言,当你开始问这些问题时,听起来你的代码中存在设计问题。你应该总是处理你不再需要的东西 - 这就是负责任的编程。
问题的可能解决方案:
不要传递Fonts
之类的对象。 在一个地方实现字体使用逻辑(一个类),将Font添加为该类的字段,并为该类实现IDisposable
。
实现字体缓存类 - 而不是使用代码中的Font
运算符创建新的new
对象,使用此类来获取所需的{ {1}}。如果可能,该类可以具有重用现有字体的逻辑。或者将最后10种字体保留在内存中,并处理其他字体。为缓存实施Font
,将在应用的生命周期中调用一次。
答案 4 :(得分:1)
终结器专门构建在类中,因为清理是必要的。无论您是要清理大量还是少量的物体,最好将它们清理干净。
GC的构建是为了拥有自己的伪脑。通过正确处理您的对象,您可以让GC执行它的操作。
但是,如果您正在创建大量的字体对象并处理所有这些字体对象,那么每隔一段时间就在相应的代(可能是0代)上调用GC以自行启动GC清理可能是有益的。你正在大量实例化的其他对象。你的目标应该是保持你知道你不会长时间使用的对象从晋升到老一代。这使GC的工作保持精益和的意思。
只要用你最好的判断就可以了。但确实要将终结器作为正常做法处理掉任何物体。
答案 5 :(得分:-2)
我至少有一个正在运行的应用程序使用.NET运行时。我不断获得OutOfMemoryExceptions。最好让您的应用程序运行,以便其他应用程序在无法获得足够资源时不会抛出异常。