Since I am writing some graphics-heavy user controls lately, I am spending a lot of time Googling for GDI related topics. Looking through the samples/demonstrations, it appears that there is some confusion about how and when to dispose GDI objects. It is common to see rendering routines where brushes/pens/fonts are created without being disposed, or GDI objects created in the control’s constructor, released (if at all) in the control’s Dispose
method. I will try to address these issues in the form of a FAQ.
Why Should GDI objects be disposed?
There is a hard limit for the total number of GDI objects available on a Windows system. For the Windows 9x family (Windows 95, 98 and ME) this limit is 1200 objects, for the NT family (Windows XP, Vista and Windows 7) the limit is 10,000. Although the number seems high, this is the total number of objects available across the system.
Whenever you create a new GDI object, you are pulling a resource out of the shared GDI resource pool, effectively decreasing the resources available to other running applications and the rest of the system. The GDI object you created cannot be used by other applications because GDI handles are private to the process that created the object.
When GDI objects are disposed, their associated handles will be freed and returned to the resource pool, to be reused when needed. This is why all GDI objects implement the IDisposable
interface.
Why should I explicitly dispose GDI objects?
After all, the garbage collector will happily clean after us, right? The answer to this question is a lot longer that one would expect. I am going to give you the short version but I encourage you to read more about the CLR garbage collector.
What makes GDI objects special is that they encapsulate unmanaged handles which cannot be simply freed by the garbage collector. A managed System.Drawing.Brush
object for example keeps a handle to an unmanaged brush object. When it is disposed, its Dispose
method calls the GdipDeleteBrush function to clean up resources used by the unmanaged brush handle. Then what happens when you do not explicitly call Dispose
? In that case, sometime after the object goes out of scope, its finalizer will kick in and call the Dispose
method for you. If you look at the Finalize
method of System.Drawing.Brush
with reflector, you will see this one line:
~Brush()
{
this.Dispose(false);
}
Why the hassle then? The framework designers made sure that unmanaged resources will be cleaned up no matter how sloppy we are. The reason is, there are two problems with finalizers. First, the exact time an object’s finalizer is executed is undefined. Actually, it is not guaranteed to be executed at all! Second, finalizers are expensive. It will require at least two garbage collections to free a finalizable object. Explicitly calling dispose overcomes both of these problems: unmanaged resources will be cleaned up immediately and the object will be exempt from finalization.
When should I dispose GDI objects?
The short answer is “as soon as possible”. For most GDI objects (pens, brushes and even fonts), the overhead of creating and disposing the object is almost non-existent. I ran a quick benchmark while writing this and here are the results:
Created 10,000 fonts in 61 milliseconds.
Created 10,000 brushes in 17 milliseconds.
Created 10,000 pens in 16 milliseconds.
If your control uses 20 fonts, brushes and fonts each, you will need a total of 0.2 milliseconds to create and dispose those objects. It doesn't really make sense keeping references to such objects; it is best to create, use and dispose them on the spot.
For some graphics objects, this may not the case. Creating an Image
for example, may take anywhere from a few milliseconds to many seconds. If you are continuously rendering the same image, you may be better off holding a reference to it to avoid the overhead. Just remember to dispose your image when you no longer need it.
How should I dispose GDI objects?
C#’s using
keyword was made for this purpose. It provides the additional benefit of calling Dispose
even when an exception is thrown inside the using
block. Its usage is as simple as this:
using (Brush brush = new SolidBrush(Color.Black))
{
graphics.FillRectangle(brush, new Rectangle(0, 0, 100, 100));
}
It also has an additional form that can be used when creating multiple objects:
using (Font font = new Font("Arial", 10.0f))
using (Brush brush = new SolidBrush(Color.Black))
{
graphics.DrawString("some text", font, brush, 0, 0);
}
There is another less useful form of the using
keyword, limited to objects of the same type:
using (Font font1 = new Font("Arial", 10.0f),
font2 = new Font("Times New Roman", 12.0f))
{
}
And a side note… It is perfectly fine to return from a function inside the using
block. Your objects will be disposed just before the return
statement is evaluated.
Summing It Up
Whenever you are creating a GDI resource, enclose it in a using
block. You can make an exception if you are sure that the object creation is expensive. In that case, keep a reference to the object and explicitly dispose it at the earliest opportunity.