Click here to Skip to main content
Click here to Skip to main content
Go to top

Disposing GDI Objects in C#. NET

, 9 Mar 2011
Rate this:
Please Sign up or sign in to vote.
This article details when, where and how to dispose of objects that create GDI object handles

Introduction

The aim of this article is to describe the importance of correctly disposing of objects that create GDI handles. It also details the types of objects which create these GDI handles, how and when to dispose of these objects and what can happen if you do not correctly dispose of them.

What are GDI Objects

GDI (Graphics Device Interface) Objects are typically objects that are used to handle drawing on a surface within an application. They may be used to hold image data such as the Bitmap object or to define how a drawing element should be styled as with the Brush object.

If you have ever done any custom drawing, such as that which you might handle with the Paint event of a Panel, then the chances are that you will have used one of these object types before. The question is, have you correctly been disposing of them? Or more importantly, why should you care?

Why it is Important to Dispose of GDI Objects

Unlike the majority of the objects in the .NET Framework, GDI handles are not automatically disposed when your application no longer holds a reference to them. This, as you may have already guessed, can lead to memory allocations that are never released. Over time (application up-time), this could lead to large consumption of memory usage and ultimately an "Out of Memory" exception.

There is however another consideration, which given the vast amounts of RAM computers use as standard, is probably going to be of greater concern - especially if you’re doing a fair amount of custom drawing.

Windows has a limit on the number of GDI handles that a session (i.e., application) is permitted to hold. This value is determined in the system registry, and by default, is set to 10,000 handles (at least this is the case in XP, Vista and 7). This value can be altered by those of you comfortable editing the registry but the maximum that can be applied is 65,536 (Windows 2000 is 16,384).

I would strongly advise you do not rely on this method, as in a production application it would be better to not change any system registry values on a customers machine. The last thing you want is to cause a customer's system problems. Either way, the following registry setting is the one of interest:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\
CurrentVersion\Windows\GDIProcessHandleQuote

*** WARNING ***
Changing the wrong registry values can seriously damage the stability of your Windows system. Do so at your own risk.

The Objects to Look Out For

The following object types are the ones to look out for, as these will cause a GDI handle to be created upon their initialisation:

  • Bitmap
  • Brush
  • DC
  • Enhanced Metafile
  • Enhanced Metafile DC
  • Font
  • Memory DC
  • Metafile
  • Metafile DC
  • Palette
  • Pen
  • Extended Pen
  • Region

(This list was obtained via the Microsoft documentation and can be found here.)

How to Dispose of These Objects

Disposing of these GDI objects can be as simple as a call to the Dispose method of the object as follows:

Bitmap bitmap = new Bitmap("mypic.bmp");
bitmap.Dispose();

The important thing to remember here is that once you have called the Dispose function, you should not try to access any of the other properties or methods of the disposed object as this will cause an exception. For example, the following would cause you problems:

Bitmap bitmap = new Bitmap("mypic.bmp");
bitmap.Dispose();
bitmap.Save("mypic.bmp");

When to Dispose of These Objects

As you can see, it is simple enough to dispose of the object, but the more important question is, when to dispose of it. Well, this of course depends on how and where you declare and use the objects. Consider the following code sample:

void EditPhoto(string filename)
{
	Bitmap bitmap = new Bitmap(filename);
	//do some image manipulation here
	bitmap.Save(filename);
	bitmap.Dispose();
}

In the above example, the bitmap object is declared within the scope of the function. In these instances, you should always dispose of the object before the function returns. If this is not done, then your application will lose the reference to the bitmap object, and you will lose the chance to dispose of the GDI handle. These kind of scenarios are known as Memory Leaks (which you can Google for more information).

But what if your reference declaration is not local to a function? Well, imagine we have a Windows Form that contains a panel in which we are drawing some basic shapes. We will use the Paint event of the panel control in order to draw on the surface of the panel using a Pen object. For performance reasons, we will want to declare our Pen object reference within the scope of the Window class, rather than inside the Paint event, in order to minimise the expensive process of creating and disposing of the Pen every time the panel needs a re-paint. The following code illustrates this:

public partial class FormPaint : Form {
Pen pen = new Pen(Color.Red);
public FormPaint()
{
	InitializeComponent();
}
private void panelPaint_Paint(object sender, PaintEventArgs e) 
{
	e.Graphics.DrawRectangle(pen, new Rectangle(10, 10, 100, 100));
}
private void FormPaint_FormClosed(object sender, FormClosedEventArgs e)
{
	pen.Dispose();
}
}

As you can see in the above example, the Pen reference is declared in the scope of the Form class so we must remember to correctly dispose of the object before the form is closed (disposed), otherwise we lose the reference and lose the chance to dispose of the GDI handle. In this example, this has been overcome by disposing of the Pen object within the FormClosed event of the Form.

Conclusion

I know most of you will probably already be aware of the issues described here, but I had to find out about this pitfall the hard way (when the bugs came calling), so hopefully this will help at least a few people out.

This is my first article, so I will look forward to any (hopefully constructive) criticisms that anyone has to offer.

Thanks for reading.

History

  • 4th March, 2011: Initial version
  • 9th March, 2011: Slight change to code snippet

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

musefan
Software Developer
United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
GeneralMy vote of 1 PinmemberDenisK14-Mar-11 7:29 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 10 Mar 2011
Article Copyright 2011 by musefan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid