Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it important to dispose SolidBrush and Pen?

I recently came across this VerticalLabel control on CodeProject.

I notice that the OnPaint method creates but doesn't dispose Pen and SolidBrush objects.

Does this matter, and if so how can I demonstrate whatever problems it can cause?

EDIT

This isn't a question about the IDisposable pattern in general. I understand that callers should normally call Dispose on any class that implements IDisposable.

What I want to know is what problems (if any) can be expected when GDI+ object are not disposed as in the above example. It's clear that, in the linked example, OnPaint may be called many times before the garbage collector kicks in, so there's the potential to run out of handles.

However I suspect that GDI+ internally reuses handles in some circumstances (for example if you use a pen of a specific color from the Pens class, it is cached and reused).

What I'm trying to understand is whether code like that in the linked example will be able to get away with neglecting to call Dispose.

And if not, to see a sample that demonstrated what problems it can cause.

I should add that I have very often (including the OnPaint documentation on MSDN) seen WinForms code samples that fail to dispose GDI+ objects.

like image 941
Joe Avatar asked Nov 30 '09 10:11

Joe


3 Answers

Of course it does matter. It is important to dispose all instances of classes that implement IDisposable when they are no longer needed. Classes are defined IDisposable when they make use of unmanaged resources, that is, operating system resources that are not handled by the .NET Framework.

If you don't manually dispose the objects, then these unmanaged resources will not be freed until the garbage collector invokes the object finalizer (and this will only happen if the class has properly implemented the Dispose pattern), which may be very late since the garbage collector only runs when it detects an actual memory shortage. Thus when not disposing objects, you are retaining operating system resources that could otherwise be used by other applications.

A discussion on this subject can be found here: http://agilology.blogspot.com/2009/01/why-dispose-is-necessary-and-other.html

like image 119
Konamiman Avatar answered Nov 15 '22 23:11

Konamiman


FWIW, in GDI there are "stock" objects. When you create a stock object you don't have delete it because it is "owned" by the OS.

You probably already know about stock objects, but here is a link that goes into some detail.

I don't know if there are similar "stock" objects in GDI+. I have just searched briefly and haven't found any references to such.

As a test I wrote a small WinForms program with a timer callback (set to fire every 10 milliseconds) like this:

private void timer1_Tick(object sender, EventArgs e)
{
  byte r = (byte)rnd.Next(0, 256);
  byte g = (byte)rnd.Next(0, 256);
  byte b = (byte)rnd.Next(0, 256);

  System.Drawing.SolidBrush sb = new SolidBrush(Color.FromArgb(0,r,g,b));
}

If I let it run, it will slowly consume memory. By watching TaskManager (not the most accurate way to gauge it), memory usage tends to grow by (on my machine, built with .NET 4.0 VS2010, Release) about 20k bytes per Task Manager update (at highest update rate). If I call Dispose on the brush, memory usage tends to grow by about 8k per Task Manager update.

Hardly a definitive test, but it seems to point to greater memory usage over time if the SolidBrush is not disposed. Interestingly, I neither Handles nor GDI Objects increased at all as the test ran (in either case). Based on past experience with leaking GDI resources, I was expecting to maybe see GDI Objects growing, particularly in the non-Dispose case.

Anyway, maybe this was informative, maybe not.

like image 40
wageoghe Avatar answered Nov 15 '22 23:11

wageoghe


I need to fix some memory leaks in an application so I've being doing some investigation. In a nutshell it seems that for most cases you get away with it with slightly higher memory use.

Below is a pathological case. I monitor my test app in task manager (crude I know) and watched the Memory (Private Working Set), Handles, USER Objects and GDI Objects columns. Button1 clicks cause higher memory use than Button2 clicks.

If I click rapidly and persistently on Button1 I can cause an 'System.OutOfMemoryException' when Memory hits about 1.6GB. Button2 never goes higher than about 12MB no matter how madly or persistently I click.

I'm on a win7 64-bit machine building a vs 2010 .net 4 client profile winforms app. Obviously you'd never normally construct millions and millions of brushes...

Regards David

private void button1_Click(object sender, EventArgs e) {
    for (int i = 0; i < 500000; i++) {
        SolidBrush b = new SolidBrush(Color.FromArgb(2, 32, 43, 128));
    }       
}

private void button2_Click(object sender, EventArgs e) {
    for (int i = 0; i < 500000; i++) {
        using (SolidBrush b = new SolidBrush(Color.FromArgb(2, 32, 43, 128))) {
        }
    }
}
like image 21
David Hollinshead Avatar answered Nov 16 '22 00:11

David Hollinshead