I recently came across this VerticalLabel control on CodeProject.
I notice that the OnPaint method creates but doesn\'t dispose Pen and SolidBrush objects.
D
The objects should be disposed of by the garbage collection after they've fallen out of scope as long as they're not referenced by anything else.
The simplest way to demonstrate whether this is happening or not (without making any code changes) is to use a large number of these controls on a form and see if the memory used by the application keeps growing or remains stable.
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.
It's just leaking un-managed resources (the pen/brush) until the corresponding managed object is reclaimed by the garbage collector. So you're wasting a few handles that aren't used afterwards anymore.
It's not too big a deal because Finalize()
will call Dispose()
but releasing unmanaged resources should usually be done rather sooner than later.
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
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))) {
}
}
}
in addition i would tell that is preferable to use the ready collections: System.Drawing.Pens. and System.Drawing.Brushes. if you not customize them in a special way.