Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Diposer for GDI+ resources (Pen, Brush, ...)

0.00/5 (No votes)
23 Oct 2009 1  
Helper class to call Dispose() of created GDI+ resources.

Introduction

The draw resource classes found inside the System.Drawing namespace (Pen, SolidBrush, ...) are actually wrapping the underling native Windows GDI resources. Like all system resources, their amount is limited, and so they should be returned to the Operating System as soon as possible.

That's why .NET documentation tells you to call the Dispose() method on Pens, Brushes etc., as soon as they are not used anymore.

Background

But .NET is a managed environment and has a garbage collector, then why do we have to manually release resources? Consider the following usual paint code:

protected override void OnPaint(PaintEventArgs e)
{
    Pen myPen1 = new Pen(Color.Black, 3);
    Pen myPen2 = new Pen(Color.Lime, 3);
    SolidBrush myBrush1 = new SolidBrush(Color.Red);
    SolidBrush myBrush2 = new SolidBrush(Color.Lime);

    // ....
    // use myPenX and myBrushX for drawing
    // ...
}

Pen and SolidBrush are internally holding unmanaged native Win32 GDI resources (HBRUSH, HPEN etc.). These are precious Windows system resources and should be released as soon as possible. When OnPaint() exits, the only references to myPenX and myBrushX are gone, so the .NET garbage collector will release the instances sometime later. This will, of course, also release the underlying native handles. But the point is, sometime later. For the time span between the last reference gone and the garbage collector releasing the unused instances, the underlying native resources are occupied although not in use anymore. This can be a problem on heavy system load situations. And, like all resources, we should use them not more than necessary, and return them as soon as we do not need them anymore.

So, we have to call Dispose() on all Pens, Brushes, etc.:

protected override void OnPaint(PaintEventArgs e)
{
    Pen myPen1 = new Pen(Color.Black, 3);
    Pen myPen2 = new Pen(Color.Lime, 3);
    SolidBrush myBrush1 = new SolidBrush(Color.Red);
    SolidBrush myBrush2 = new SolidBrush(Color.Lime);

    // ....
    // use myPen and myBrush for drawing
    // ...

    myPen1.Dispose();
    myPen2.Dispose();
    myBrush1.Dispose();
    myBrush2.Dispose();
}

If you have a complicated drawing routine incorporating many pens and brushes, calling Dispose() on all instances can be a tedious and error prone task. You easily add a new brush in the middle of your code and forget to call Dispose() on it before method exit. And be aware: if an exception is thrown somewhere in your drawing code, the control flow can jump out of OnPaint() without running to its end. So, the Dispose() of your instances will not be called at all.

C# provides the using statement for this situation:

protected override void OnPaint(PaintEventArgs e)
{
    using (Pen myPen1 = new Pen(Color.Black, 3))
    using (Pen myPen2 = new Pen(Color.Lime, 3))
    using (SolidBrush myBrush1 = new SolidBrush(Color.Red))
    using (SolidBrush myBrush2 = new SolidBrush(Color.Lime))
    {
        // use myPenX and myBrushX for drawing
    }
    // here all resources created inside using() are diposed,
    // also in case of an exception or return statement
}

This solves the problem perfectly for simple OnPaint() methods. But if there is more complicated painting involving different paint resources depending on the control's state, we have to create all possibly used resources before painting:

protected override void OnPaint(PaintEventArgs e)
{
    using (Pen myPen1 = new Pen(Color.Black, 3))
    using (Pen myPen2 = new Pen(Color.Lime, 3))
    using (SolidBrush myBrush1 = new SolidBrush(Color.Red))
    using (SolidBrush myBrush2 = new SolidBrush(Color.Lime))
    {
        if ( some condition )
        {
            // use myPen, myBrush1 and myBrush2, myPen2 is not used
            if ( some other condition )
            {
                // use myPen2
            }
        }
        else
        {
            // use myPen1 and myBrush1 for drawing,
            // myPen2 and myBrush2 are never used
        }
    }
    // here all resources created inside using()
    // are diposed, also in case of an exception or return
}

Of course, this is not a big deal if only one brush or pen is unnecessarily created. I do visualizations for industrial processes, and there we use sophisticated user controls involving a lot of complicated painting using many different resources. And, there are two big 1600x1080 screens showing many of those controls on the same time. All the needless draw resources created have a measurable impact on the system performance. To avoid this, we would end with something like this:

protected override void OnPaint(PaintEventArgs e)
{
    using (Pen myPen1 = new Pen(Color.Black, 3))
    using (SolidBrush myBrush1 = new SolidBrush(Color.Red))
    {
        if ( some condition )
        {
            using (SolidBrush myBrush2 = new SolidBrush(Color.Lime))
            {
                // use myPen1, myBrush1 and myBrush2
                if ( some other condition )
                {
                    using (Pen myPen2 = new Pen(Color.Lime, 3))
                    {
                        // use myPen2
                    }
                    // here myPen2 is disposed
                 }
            }
            // here myBrush2 is disposed
        }
        else
        {
            // use myPen1 and myBrush1 for drawing, myPen2 and myBrush2 are never used
        }
    }
    // here myPen1 and myBrush1 are disposed
}

So far, so good. But imagine the code we are ending up with if there are 6 conditions and 12 draw resources, some of them used in all control paths, some in only one, some in three of them, and so on. The resulting construct of nested using statements is hard to read and even harder to maintain. If the drawing code changes and a resource used before only in one control path is newly used in another control path too, we have to rearrange the whole code.

Helper class to dispose drawing resources on method exit

I have a strong C++ background, and in C++, it is a best practice to encapsulate resources in objects to get them released as soon as they go out of scope. This is especially important to make code exception safe. So, I ported the C++ approach to C#: have a helper class releasing resources.

using System;
using System.Collections.Generic;

class Disposer : IDisposable
{
    private List<IDisposable> m_disposableList = 
            new List<IDisposable>();
    private bool m_bDisposed = false;

    // default ctor
    public Disposer()
    {
    }

    public void Add(IDisposable disposable)
    {
        if (m_bDisposed)
        {
            // its not allowed to add additional items
            // to dispose if Dispose() already called
            throw new InvalidOperationException(
              "Disposer: tried to add items after call to Disposer.Dispose()");
        }
        m_disposableList.Add(disposable);
    }

    #region IDisposable members
    public void Dispose()
    {
        if (!m_bDisposed)
        {
            foreach (IDisposable disposable in m_disposableList)
            {
                disposable.Dispose();
            } 
            m_disposableList.Clear(); 
            m_bDisposed = true;
        }
    } 
    #endregion
}

All drawing resource classes in the System.Drawing namespace implement the IDisposable interface. It declares a method, Dispose(). For details, see the MSDN documentation on IDisposable. We add all object instances to be disposed to an instance of Disposer, which iterates the internal list and calls Dispose() on all entries. Be aware that this code is not thread safe. For this, m_disposableList and m_bDisposed would need to be protected with a lock(). The intended use case for this helper class is inside user controls, where all members have to be accessed from the thread which initially created the control anyway.

Usage of the Disposer helper class

Now, the OnPaint() method is changed to use the Disposer helper class:

protected override void OnPaint(PaintEventArgs e)
{
    using (Disposer drawResDisposer = new Disposer())
    {
        Pen myPen1 = new Pen(Color.Black, 3);
        drawResDisposer.Add(myPen1);
        SolidBrush myBrush1 = new SolidBrush(Color.Red);
        drawResDisposer.Add(myBrush1);

        if ( some condition )
        {
            SolidBrush myBrush2 = new SolidBrush(Color.Red);
            drawResDisposer.Add(myBrush2);
            // use myPen1, myBrush1 and myBrush2
            if ( some other condition )
            {
                Pen myPen2 = new Pen(Color.Yellow, 3);
                drawResDisposer.Add(myPen2);
                // draw using myPen2
            }
        }
        else
        {
            // use myPen1 amyBrush1 for drawing,
            // myPen2 and myBrush2 is never used
        }
        // here all resources added to drawResDisposer
        // in any control path are disposed
    }

Just add every instantiated drawing object to the Disposer, drawResDisposer, and on exit of the code block surrounded by using {}, drawResDisposer.Dispose() is called automagically, which calls the Dispose() of all the instances added to it. No need to know which of the draw resources where actually needed and created. Just add them to the disposer, use them, and forget about them. I think this is a much cleaner and easier to maintain code structure.

The Disposer class can also be used for every other class encapsulating native and unmanaged resources. As long as the class implements the IDisposable interface.

I am a fan of one single kind of programmer laziness only: Don't do things manually which can be done by the compiler or the runtime automatically.

Improving the Disposer with WeakReference

In advanced user controls, we should not create all drawing resources on each call of OnPaint(). Painting occurs quite frequently in situations like resizing. It is a waste of resources to create a pen every time it is used and then hand it over to the garbage collector for destruction directly. Each drawing resource should be created on first use, and disposed inside the control's Dispose() method. In other words, we create a singleton for each different drawing resource type used for painting. This way, the resources are held by the control during its lifetime, but this is still better than constructing and destroying the same drawing resources over and over again. But, this approach makes the problem even worse: the resources are now created and destroyed in different methods of the control class, so it is much harder to get the Dispose() of each resource called inside the control's Dispose() method. If we fail to dispose the disposer instance when the control gets destroyed, the internally existing references to the IDisposable instances stop the garbage collector from freeing them. Less than better...

To make the disposer helper class more useful in such situations, it is changed to use the .NET System.WeakReference class. It allows the garbage collector to free an object although there is still a reference, a weak one. See the MSDN documentation for details. This class is made for such kind of situations: a reference to an object which can be used to dispose it but does not count itself as a reference for the garbage collector.

using System;
using System.Collections.Generic;

class Disposer : IDisposable
{
    private List<WeakReference> m_disposableList = 
            new List<WeakReference>();
    private bool m_bDisposed = false;

    // default ctor
    public Disposer()
    {
    }

    public void Add(IDisposable disposable)
    {
        if (m_bDisposed)
        {
            // its not allowed to add additional items
            // to dispose if Dispose() already called
            throw new InvalidOperationException(
              "Disposer: tried to add items after call to Disposer.Dispose()");
        }
        m_disposableList.Add(new WeakReference(disposable));
    }

    #region IDisposable members
    public void Dispose()
    {
        if (!m_bDisposed)
        {
            foreach (WeakReference weakRef in m_disposableList)
            {
                try
                {
                    if (weakRef.IsAlive)
                    {
                        // sadly there is no generic version of WeakReference
                        // WeakReference<IDisposable> would be nice...
                        IDisposable strongRef = (IDisposable)weakRef.Target;
                        // strongRef is null if weakRef.Target already disposed
                        if (strongRef != null)
                        {
                            strongRef.Dispose();
                        }
                    }
                } 
                catch (System.InvalidOperationException ex)
                {
                    // weakRef.Target already finalized
                }
            }
        } 
        m_disposableList.Clear(); 
        m_bDisposed = true;
    }
    #endregion
}

Here is the usage of the improved class inside a control:

class MyControl : UserControl
{
    private Disposer m_Disposer = new Disposer();

    private Pen m_Pen1 = null;
    private Pen1
    {
        get
        {
            if (m_Pen1 == null)
            {
                m_Pen1 = new Pen(Color.Lime, 5);
                m_Disposer.Add(m_Pen1);
            }
            return m_Pen1;
        }
    }

    private SolidBrush m_Brush1 = null;
    private Brush1
    {
        get
        {
            if (m_Brush1 == null)
            {
                m_Brush1 = new SolidBrush(Color.Red);
                m_Disposer.Add(m_Brush1);
            }
            return m_Brush1;
        }
    }

    //
    // ... many other pens, brushes, fonts, we draw a copmlicated control
    //

    protected override void OnPaint(PaintEventArgs e)
    {
        // ...
        // use the same singleton on every call
        e.Graphics.DrawLine(this.Pen1, point1, point2);
        e.Graphics.FillRectangle(this.Brush1, rect);
        // ...
    }

    #region IDisposable members
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (components != null)
            {
                components.Dispose();
            }
            m_Disposer.Dispose()
            base.Dispose(disposing);
        }
    }
    #endregion

    //
    // ...
    //
}

All you have to is add the lines shown in bold. If you forget the call to m_Disposer.Dispose(), the garbage collector will take care of the draw resources. The references held inside the disposer class do not count for the garbage collector anymore. This is exactly what we want.

Points of interest

This possible usage of the using keyword is often overseen:

// myType is any type implementing IDisposable
using (myType myVar = new myType())
{

    // ...
    // code here making use of myVar
    // ...
}

If the code block following using() is left on any path, including an exception, a return in the middle etc., myVar.Dispose() is called implicitly. The needed calls are inserted by the C# compiler. The only restriction for types used in using() is that they implement IDisposable.

The using statement is actually just syntactic sugar which is extended by the C# compiler to the following code. You can see this if you inspect your binary assembly with Reflector:

try
{
    // myType is any type implementing IDisposable
    myType myVar = new myType();

    // ...
    // code here making use of myVar
    // ...

}
catch (System.Exception ex)
{

}
finally
{
    myVar.Dispose();
}

Conclusion

Although no resources will really be leaked by not calling Dispose() on GDI wrapper classes, it's a good habit to do so. This way, they are released when they are not needed anymore, and not sometime later when the garbage collector is run the next time.

Better idea?

I'm aware of the fact that this is a C++ approach. I'm relatively new to C#, but did C and C++ since more than a decade before. So, if you have a more "C#-ish" way to do this, please tell me.

History

  • 07/07/2009 - Initial version.
  • 10/13/2009 - WeakReference version added, some minor text additions.
  • 10/22/2009 - Reworked code samples to better show the intended use case.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here