tags:

views:

748

answers:

2

I am investigating a GDI resource leak in a large application. In order to further my understanding of how these problems occur, I have created a very small application which I have deliberately made 'leaky'. Here is a simple user control which should result in the creation of 100 Pen objects:

public partial class TestControl : UserControl
{
    private List pens = new List();

    public TestControl()
    {
        InitializeComponent();

        for (int i = 0; i < 100; i++)
        {
            pens.Add(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))));
        }

        this.Paint += new PaintEventHandler(TestControl_Paint);
    }

    void TestControl_Paint(object sender, PaintEventArgs e)
    {
        for (int i = 0; i < 100; i++)
        {
            e.Graphics.DrawLine(pens[i], 0, i, Width, i);
        }
    }
}

However, when I create an instance of my object and add it to a form, looking at my application with TaskManager I currently see ~37 GDI objects. If I repeatedly add new TestObject user controls to my form, I still only see ~37 GDI objects.

What is going on here! I thought that the constructor for System.Drawing.Pen would use the GDI+ API to create a new Pen, thus using a new GDI object.

I must be going nuts here. If I cannot write a simple test application that creates GDI objects, how can I create one which leaks them!

Any help would be much appreciated.

Best Regards, Colin E.

+1  A: 

Does the GDI+ use GDI handles? I'm not sure, though I read somewhere that there is a .NET System.Drawing implementation that relies on bare GDI.

However, maybe you can try to find your leaks with a profiler like AQTime instead.

How are you sure your large app is leaking GDI handles? Is the count in Task Manager large? If so, are you always using GDI+, or also GDI? Does your test app GDI handle count increase if you create your control multiple times?

OregonGhost
Thanks for the response. Yes, that was my suspicion that GDI+ is not always using GDI handles. I am sure the large application leaks GDI handles. It uses a large number (>500) and this increases over time.As to whether we are using GDI+ all the time, we only use System.Drawing which I presume only uses GDI+ - is that correct?Thanks.
... related to this, if System.Drawing.Pen does not use a GDI handle, what resource am I freeing by Disposing of it? Sorry if my one question has become three!
I'm actually not sure. I read somewhere, as mentioned, that there is a System.Drawing implementation using GDI, while one would typically expect System.Drawing to use GDI+. Might have been on Windows CE or something. I'm also not sure whether creating window handles (forms and controls) can increase GDI handle count. In many instances when I was leaking some kind of handles, it was because of leaked controls rather than GDI+ things.
OregonGhost
@Pen.Dispose: You are freeing the System.Drawing resource, and it is not your duty to find out what that exactly is. Can be the underlying GDI+ object, a GDI handle or some other thing.
OregonGhost
+2  A: 

You are not really leaking resources in your sample. Remove this code from your Load event:

for (int i = 0; i < 100; i++)
    {
        pens.Add(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))));
    }

Your Paint event handler should look like this:

void TestControl_Paint(object sender, PaintEventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        e.Graphics.DrawLine(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))), 0, i, Width, i);
    }
}

Now you will be leaking in every paint call. Start minimizing/restoring your Form and see GDI objects sky rocket...

Hope this helps.

DevComponents - Denis Basaric
Hi Denis ... nice try, but have you actually tested this? I gave it a go and my application still only used a handful of GDI objects. This does not make sense!