17

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?

Dan Lew
  • 85,990
  • 32
  • 182
  • 176
Joe White
  • 94,807
  • 60
  • 220
  • 330

6 Answers6

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

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • "Often, unmanaged handles are more restricted than memory" -- Sure. But is that true for GDI+ font handles specifically? That's part of my question. – Joe White Apr 15 '09 at 16:11
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.

David Hill
  • 4,102
  • 2
  • 23
  • 19
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.

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
  • 7
    Why wouldn't you dispose of it? Well the OP did say why: because it would tremendously simplify his code. –  Apr 15 '09 at 16:56
  • 2
    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? – supercat Dec 22 '10 at 16:44
  • @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. – Jeff Yates Dec 22 '10 at 18:00
  • 2
    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. – supercat Dec 22 '10 at 21:50
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.

Igor Brejc
  • 18,714
  • 13
  • 76
  • 95
  • 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? – Arafangion Jan 30 '13 at 01:34
  • 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. – Igor Brejc Jan 30 '13 at 08:54
  • 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? – Arafangion Jan 30 '13 at 13:58
  • 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. – Igor Brejc Jan 31 '13 at 16:53
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.

TheHolyTerrah
  • 2,859
  • 3
  • 43
  • 50
-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.

Andy
  • 1