Click here to Skip to main content
15,890,527 members
Articles / Programming Languages / C++/CLI

Using GDI Objects the Right Way

Rate me:
Please Sign up or sign in to vote.
4.20/5 (7 votes)
23 Dec 2009Apache4 min read 35.9K   14   8
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.

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:

C++
~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:

C++
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:

C#
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:

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

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Turkey Turkey
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
Mahdi Nejadsahebi30-Apr-11 21:11
Mahdi Nejadsahebi30-Apr-11 21:11 
QuestionGDI limit incorrect/misleading? Pin
IainWildman4-Jan-10 5:04
IainWildman4-Jan-10 5:04 
AnswerRe: GDI limit incorrect/misleading? Pin
Ozgur Ozcitak12-Jan-10 6:58
Ozgur Ozcitak12-Jan-10 6:58 
GeneralIDisposable Pin
Ian Good2-Jan-10 17:25
Ian Good2-Jan-10 17:25 
GeneralRe: IDisposable Pin
Ozgur Ozcitak4-Jan-10 4:48
Ozgur Ozcitak4-Jan-10 4:48 
Generalusing ... return Pin
Ian Good2-Jan-10 17:17
Ian Good2-Jan-10 17:17 
Generaluser controls Pin
Ivan Ičin28-Dec-09 12:59
Ivan Ičin28-Dec-09 12:59 
GeneralRe: user controls Pin
Ozgur Ozcitak28-Dec-09 14:22
Ozgur Ozcitak28-Dec-09 14:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.