How important is disposing a Font, really?
Asked Answered
S

6

18

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?

Sugarplum answered 15/4, 2009 at 15:51 Comment(0)
F
5

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.

Fighterbomber answered 15/4, 2009 at 15:58 Comment(0)
H
5

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...

Hammers answered 15/4, 2009 at 15:57 Comment(1)
"Often, unmanaged handles are more restricted than memory" -- Sure. But is that true for GDI+ font handles specifically? That's part of my question.Sugarplum
F
5

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.

Fighterbomber answered 15/4, 2009 at 15:58 Comment(0)
B
5

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:

Always call Dispose before you release your last reference to the Font. Otherwise, the resources it is using will not be freed until the garbage collector calls the Font object's Finalize method.

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.

Barnyard answered 15/4, 2009 at 16:52 Comment(4)
Why wouldn't you dispose of it? Well the OP did say why: because it would tremendously simplify his code.Envy
When a control's Font property (or Picture property, or whatever) is set to an object I hold, in what cases does the control make a copy of the object (in which case I should dispose of mind, and let it dispose of its), and in what cases does the control expect to keep using the object passed in? If I had my druthers, there'd be a way of specifying whether a control should assume ownership of a passed-in object, but since there isn't, what should one do?Guileless
@supercat: The documentation should indicate to you what the rules are regarding ownership. However, you should at least assume that while the control is referencing the Font, you shouldn't Dispose it. I would expect, however, that the Control disposes the font when it gets disposed, but I don't know for sure.Barnyard
The Control.Font property documentation says nothing about ownership; experimentation suggests that particular property is agnostic with regard to disposal. A control won't dispose of its font property, but won't care if the assigned font is disposed (even if it's disposed before it's assigned!). It would seem that if one wants a font only for purpose of setting control font properties, one could pre-dispose the font, but that somehow feels wrong. I'm not sure how best to handle the Image property of a Picturebox, though, since those do care about disposal.Guileless
M
3

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 implement IDisposable for that class.

  • Implement a Font cache class - instead of creating new Font objects using the new operator all over your code, use this class to get the desired Font. 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. Implement IDisposable for the cache, which will be called once in your app's lifecycle.

Mutineer answered 16/4, 2009 at 18:24 Comment(4)
How would the Font Cache class know when the fonts are not being used anymore? Would you have to "return" the font to the cache?Tolerant
Yes, there would have to be a way of telling it you don't need the font any longer. I usually do this using some sort of a Lease class that implements IDisposable, and in the Dispose() method it contacts the cache and tells it to decrease the reference count. The same pattern can be used for factories.Mutineer
Isn't that back to square one, then? At least, though, you do now have a manager that manages your presumably expensive fonts, but that does beg the question: Why shouldn't you just assume that the constructor/factory and the garbage collector can't do the task in the majority of situations?Tolerant
The difference is that you don't really have to know (or care) what happens with resources. The factory could destroy them or just cache them for later use. And you can later change the behavior. Whether you really need this pattern is a question of how expensive your resources are and how often you require them. In case of complex GDI rendering, fonts get reused a lot (thousands of times for a single Paint call) and this definitely speeds things up.Mutineer
K
1

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.

Karakalpak answered 15/4, 2009 at 17:23 Comment(0)
A
-2

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.

Agiotage answered 20/2, 2013 at 0:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.