处理字体真的有多重要?
我知道最好的做法是在任何实现 IDisposable 的对象上调用 Dispose,尤其是包装有限资源(如文件句柄、套接字、GDI 句柄等)的对象。
但是我遇到了这样的情况:我有一个对象有一个 Font,我必须通过几层对象来探索 IDisposable,并检查大量用法,以确保我总是得到 Font 的处理。 我想知道是否值得这么复杂。
如果 Font 包装 HFONT 则是一回事,因为 GDI 资源是系统全局的。 但 Font 不包装 GDI 句柄; 它是GDI+,它是一个完全独立的系统,据我了解,它是进程本地的,而不是像GDI那样是系统全局的。 与 Image 不同,Font 永远不会占用文件系统资源(无论如何,据我所知)。
所以我的问题是:让字体被垃圾收集的真正成本是多少?
我知道我会对终结器造成一点影响,但如果“泄露”的字体数量很少(比如六个),那么老实说,这种影响不会引人注目。 除了终结器之外,这似乎与分配一个中等大小的数组并让 GC 清理它没有太大区别——它只是内存。
让字体获得 GC 认证是否会产生我不知道的成本?
I'm aware that the best practice is to call Dispose on any object that implements IDisposable, especially objects that wrap finite resources like file handles, sockets, GDI handles, etc.
But I'm running into a case where I have an object that has a Font, and I would have to plumb IDisposable through several layers of objects, and review a lot of usages, to make sure I always get the Font disposed. And I'm wondering whether it's worth the complexity.
It would be one thing if Font wrapped an HFONT, because GDI resources are system-global. But Font doesn't wrap a GDI handle; it's GDI+, which is a completely separate system, and as far as I understand, is process-local, not system-global like GDI. And unlike Image, Font doesn't ever hold onto filesystem resources (that I know of, anyway).
So my question is: What is the real cost of letting a Font get garbage collected?
I know I would take a small hit for the finalizer, but if the number of "leaked" Fonts is small (say half a dozen), that hit honestly wouldn't be noticeable. Apart from the finalizer, this doesn't seem much different from allocating a mid-sized array and letting the GC clean it up -- it's just memory.
Are there costs I'm not aware of in letting a Font get GCed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
简单的回答:如果只有几个,那就不会。 如果很多,那么是的。 如果您的应用程序已经给垃圾收集器带来了压力,那么可以。 我会使用 perfmon 查看周围的对象数量,以及晋升到更高几代的对象数量,然后做出决定。
Simple answer: if its just a few, then no. If it's a lot, then yes. If your application is already stressing the garbage collector, then yes. I would use perfmon to view the number of objects sitting around, and the number getting promoted to higher generations, and then decide.
问题是垃圾收集仅在存在内存压力时才会发生。 通常,非托管句柄比内存受到更多限制,因此您可能会在 GC 发生之前用完句柄,从而导致错误。
但对于一两个
Font
实例,它不会对您造成太大伤害。一个更大的问题是一些对象是共享的,不应该(或不能)过早地处理......
The problem is that garbage collection only happens when there is memory pressure. Often, unmanaged handles are more restricted than memory, so you can run out of handles before GC happens, causing errors.
But for one or two
Font
instances, it won't hurt you overly.A bigger problem is that some of the objects are shared and shouldn't (or can't ) be disposed prematurely...
完成后为什么不把它扔掉呢? 仅仅因为我们有街道清洁工,并不意味着我们就应该在街道上乱扔垃圾。 但是,在给出的示例中,如果在对象的生命周期内需要该字体,则在该对象的处置中处置该字体。 有很多事情也可以简化我的代码,但这并不能证明这些更改是合理的——有时有些事情你应该做,即使这很痛苦。
整理好自己总是一个好主意。 当你不再需要某样东西时,就把它扔掉。 这样您就可以避免令人讨厌的竞争条件、内存不足异常、绘图故障以及冗长的处理器密集型垃圾收集。
我发现,如果您不再需要一次性物品,最好将其丢弃,除非有正当理由不这样做(例如您不拥有该物品)。 追踪问题的根本原因比预先进行防御性编码更困难。
关于字体,MSDN 说:
它没有说明资源是什么,但事实上它们明确指出应该隐式完成此操作,这一事实增加了调用 Dispose 的重要性。
Why wouldn't you dispose of it once you're done? Just because we have street sweepers doesn't mean we should just go around littering the streets. However, in the example given, if the font is needed for the lifetime of the object then dispose of the font in that object's dispose. There are many things that would simplify my code too, but that doesn't justify those changes - sometimes there are things that you should do, even though it's a pain.
It's always a good idea to tidy up after yourself. When you no longer need something, dispose of it. That way you can avoid nasty race conditions, out of memory exceptions, drawing glitches, and lengthy, processor-intensive garbage collections.
I find that it's best practice to dispose of disposable objects if you no longer need them unless there is a justifiable reason not to (such as you don't own the object). It is more difficult to track down the root cause of a problem than it is to code defensively up front.
With regards to Font, MSDN says:
It doesn't say what the resources are but the fact that they explicitly state that this should be done implicitly adds importance to calling Dispose.
处理掉任何东西真的有多重要? 恕我直言,当您开始问此类问题时,听起来您的代码中存在设计问题。 你应该总是处理掉不再需要的东西——这就是所谓的负责任的编程。
问题的可能解决方案:
不要传递诸如
字体
之类的对象。 在一个地方实现字体使用逻辑(一个类),将 Font 添加为该类的字段,并为该类实现IDisposable
。实现 Font 缓存类 - 不要在代码中使用
new
运算符创建新的Font
对象,而是使用此类来获取所需的字体
。 如果可能的话,该类可以具有重用现有字体的逻辑。 或者将最后 10 种字体保留在内存中,并丢弃其他字体。 为缓存实现IDisposable
,它将在应用的生命周期中调用一次。How important is disposing of anything, really? IMHO when you start asking these kind of questions, it sounds like you're having a design problem in your code. You should always dispose of things you don't need anymore - that's called responsible programming.
Possible solutions to your problem:
Do not pass around objects like
Fonts
. Implement the font-using logic in one place (one class), add the Font as a field of that class and implementIDisposable
for that class.Implement a Font cache class - instead of creating new
Font
objects using thenew
operator all over your code, use this class to get the desiredFont
. The class can then have the logic to reuse existing Fonts, if possible. Or to keep last 10 fonts in memory, and dispose of the others. ImplementIDisposable
for the cache, which will be called once in your app's lifecycle.终结器专门内置于类中,因为清理是必要的。 无论您有大量还是少量的物体需要清理,清理它们都是很好的做法。
GC 的构建是为了拥有自己的伪思维。 通过正确地处理你的对象,你就可以让 GC 完成它被设计的任务。
但是,如果您要创建大量字体对象并处理所有这些对象,那么经常在适当的代(可能是第 0 代)上调用 GC 来根据类型自行启动 GC 清理可能会有所帮助。您正在实例化大量的其他对象。 您的目标应该是防止您知道自己不会长期使用的对象被提升到老一代。 这使得 GC 的工作变得精简且高效。 意思是。
只要运用你最好的判断力,你就会没事的。 但确实要按照常规做法使用终结器处理任何对象。
Finalizers are built into classes specifically because the cleanup is necessary. Regardless of whether you have a large or small amount of objects to clean up, it's good practice to clean them up.
The GC was built to have a pseudo-mind of its own. By properly disposing of your objects, you're allowing the GC to do what it was made to do.
However, if you're creating a large number of font objects and disposing of all of them, it may be beneficial to call the GC on the appropriate generation (probably generation 0) every so often to initiate a GC cleanup yourself depending on what kinds of other objects you're instantiating in great number. Your goal should be to keep objects you know you're not using for very long from getting promoted to elder generations. This keeps the GC's job lean & mean.
Just use your best judgement and you'll be fine. But do indeed dispose of any object with a finalizer as your normal practice.
我至少还有一个使用 .NET 运行时的其他应用程序正在运行。 我不断收到 OutOfMemoryExceptions。 最好让您的应用程序表现良好,以便其他应用程序在无法获取足够资源时不会抛出异常。
I have at least one other app running that uses the .NET runtime. I keep getting OutOfMemoryExceptions. Its would be good to make your application behave so other apps don't throw exceptions when they can't get enough resources.