PC Review


Reply
Thread Tools Rate Thread

BUG in System.Drawing.Font!

 
 
Barry Anderberg
Guest
Posts: n/a
 
      12th May 2004
I'm using the .NET Memory Profiler by Sci Tech and I wrote a little
test application to verify something odd I observed and it appears
that System.Drawing.Font fails to dispose of its FontFamily.

I run the following code:

// BEGIN
while( true )
{
System.Drawing.Graphics dc=lblClock.CreateGraphics();
dc.Clear(Color.White);
Font f=new Font("Arial", 10, FontStyle.Bold);
dc.DrawString(DateTime.Now.ToString("yyyy MMM dd, hh:mm:ss",
ClockDTFI), f, Brushes.Black, 5, 0);
f.Dispose();
dc.Dispose();
}
// END

This is just to see if I can generate lots of fonts, dispose of them,
and verify that they are disposing of their unmanaged resources, but
the .NET Memory Profiler shows that there are *thousands* of
FontFamily objects that haven't been disposed.

I am not certain but I suspect this is causing a memory leak because
my program's memory grows and grows.

Even if I call f.FontFamily.Dispose() it still says there are
thousands of FontFamily objects that haven't been disposed.
 
Reply With Quote
 
 
 
 
Chris R. Timmons
Guest
Posts: n/a
 
      13th May 2004
(E-Mail Removed) (Barry Anderberg) wrote in
news:(E-Mail Removed):

> I'm using the .NET Memory Profiler by Sci Tech and I wrote a
> little test application to verify something odd I observed and
> it appears that System.Drawing.Font fails to dispose of its
> FontFamily.
>
> I run the following code:
>
> // BEGIN
> while( true )
> {
> System.Drawing.Graphics dc=lblClock.CreateGraphics();
> dc.Clear(Color.White);
> Font f=new Font("Arial", 10, FontStyle.Bold);
> dc.DrawString(DateTime.Now.ToString("yyyy MMM dd, hh:mm:ss",
> ClockDTFI), f, Brushes.Black, 5, 0);
> f.Dispose();
> dc.Dispose();
> }
> // END
>
> This is just to see if I can generate lots of fonts, dispose of
> them, and verify that they are disposing of their unmanaged
> resources, but the .NET Memory Profiler shows that there are
> *thousands* of FontFamily objects that haven't been disposed.
>
> I am not certain but I suspect this is causing a memory leak
> because my program's memory grows and grows.
>
> Even if I call f.FontFamily.Dispose() it still says there are
> thousands of FontFamily objects that haven't been disposed.


Barry,

It's not a memory leak. Unmanaged resources and memory are two
different things. The calls to IDisposable.Dispose are properly
freeing the unmanaged resources (i.e. the low level font handles).
Otherwise, you would be getting some kind of exception about no
available handles.

The memory used by the Graphics and Font instances is managed by the
Garbage Collector (GC). It simply hasn't gotten around to reclaiming
the memory used by those objects. If you're an experienced C, C++ or
Delphi developer, it may be hard to ignore the growing memory usage,
but that's usually the best thing to do. The GC is a very well
written piece of software. Trust it to do its job.

MSDN has several good articles explaining how the GC works:


http://msdn.microsoft.com/msdnmag/is...00/GCI/TOC.ASP

http://msdn.microsoft.com/msdnmag/is...0/GCI2/TOC.ASP

http://msdn.microsoft.com/library/en-
us/dndotnet/html/dotnetgcbasics.asp

(TinyURL: http://tinyurl.com/2tzpn)

http://msdn.microsoft.com/library/en-
us/dndotnet/html/dotnetperftechs.asp

(TinyURL: http://tinyurl.com/3890)


Hope this helps.

Chris.
-------------
C.R. Timmons Consulting, Inc.
http://www.crtimmonsinc.com/
 
Reply With Quote
 
Barry Anderberg
Guest
Posts: n/a
 
      13th May 2004
Chris,

I am not sure I agree with you. I am familiar with the GC and how/when
it collects garbage. It collects once the managed heap is full, and at
some other times. So I wrote the test application to deliberately fill
the heap to force a garbage collection. I also added a button to the
form to call GC.Collect() and according to the memory profiler, these
objects have not been disposed. I realize that they have been garbage
collected, but that does not mean there are no leaks. If unmanaged
resources are not freed, the garbage collector will not do it for you.
The unmanaged resources are freed by the underlying framework code when
the object is disposed, or in the finalize method of the class in
question. The only thing I can assume is that the finalize method is
doing the job, but I still think it's a bug in the framework that the
Dispose method of the Font's objects aren't being called. Any class
that implements IDisposable should have its dispose method called. The
finalize method is a last resort when the programmer does not call
Dispose like he should. Isn't that your understanding as well?

Again, you're probably right that there's no leak but it makes for
considerable confusion when running a memory profiler that tracks
undisposed objects. We have a major piece of software at my job and it
is slowly eating up the memory and eating up the entire pagefile causing
major fragmentation of the pagefile, ultimately slowing down the system
and causing other remoted applications to begin timing out. I've been
spending lots of time pouring over code and running this memory profiler
and I'm at a loss as to why this is happening. The FontFamily class is
only one of many objects that the .NET framework is not disposing of
even though the classes implement IDisposable. That's simply bad
programming on the part of Microsoft. One thing to note is that we're
using the 1.0 Framework which may explain these issues. Perhaps the
objects are being properly disposed of in the newer .NET Framework.

Thanks for the reply,

Barry



*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
 
Reply With Quote
 
Chris R. Timmons
Guest
Posts: n/a
 
      13th May 2004
Barry Anderberg <(E-Mail Removed)> wrote in
news:#(E-Mail Removed):

> Chris,
>
> I am not sure I agree with you. I am familiar with the GC and
> how/when it collects garbage. It collects once the managed heap
> is full, and at some other times. So I wrote the test
> application to deliberately fill the heap to force a garbage
> collection. I also added a button to the form to call
> GC.Collect() and according to the memory profiler, these objects
> have not been disposed. I realize that they have been garbage
> collected, but that does not mean there are no leaks. If
> unmanaged resources are not freed, the garbage collector will
> not do it for you. The unmanaged resources are freed by the
> underlying framework code when the object is disposed, or in the
> finalize method of the class in question. The only thing I can
> assume is that the finalize method is doing the job, but I still
> think it's a bug in the framework that the Dispose method of the
> Font's objects aren't being called. Any class that implements
> IDisposable should have its dispose method called. The finalize
> method is a last resort when the programmer does not call
> Dispose like he should. Isn't that your understanding as well?
>
> Again, you're probably right that there's no leak but it makes
> for considerable confusion when running a memory profiler that
> tracks undisposed objects. We have a major piece of software at
> my job and it is slowly eating up the memory and eating up the
> entire pagefile causing major fragmentation of the pagefile,
> ultimately slowing down the system and causing other remoted
> applications to begin timing out. I've been spending lots of
> time pouring over code and running this memory profiler and I'm
> at a loss as to why this is happening. The FontFamily class is
> only one of many objects that the .NET framework is not
> disposing of even though the classes implement IDisposable.
> That's simply bad programming on the part of Microsoft. One
> thing to note is that we're using the 1.0 Framework which may
> explain these issues. Perhaps the objects are being properly
> disposed of in the newer .NET Framework.


Barry,

I think I duplicated your bug in .Net 1.1.

Depending upon the Font constructor used, each instance of the Font
class creates one or two instances of the FontFamily class for its
own internal use, but never disposes of them.

This code results in two FontFamily instances being created (and not
disposed of):

Font f = new Font("Arial", 10, FontStyle.Bold);
...
f.Dispose();

Whereas passing an existing instance of FontFamily to the Font
constructor only results in one undisposed instance of FontFamily:

FontFamily fontFamily = new FontFamily("Arial");
Font f = new Font(fontFamily, 10, FontStyle.Bold);
...
f.Dispose();
fontFamily.Dispose();

If you want to dig into the .Net framework source code, there is a
great utility called Reflector available at:

http://www.aisto.com/roeder/dotnet/

With it, you can view the decompiled C# source of all of the methods
of the Font and FontFamily classes (and all the rest of the .Net
framework.)

At this point, about the only constructive advice I can offer is the
obvious: minimize the number of instances that don't get properly
disposed. Something like creating a handful of global Font instances
and re-using them throughout the app.

FWIW, here's a short program that demonstrates the problem:

// Compile with "csc /t:exe example.cs"

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TestNamespace
{
public class TestClass
{
[STAThread]
public static void Main()
{
using (Label lblClock = new Label())
{
using (Graphics dc = lblClock.CreateGraphics())
{

// The Font instances get disposed of OK, but
// there will be 2000 undisposed instances of
// FontFamily.

for (int i = 0; i < 1000; i++)
{
dc.Clear(Color.White);
using (Font f = new Font("Arial", 10, FontStyle.Bold))
{
dc.DrawString(DateTime.Now.ToString(
"yyyy MMM dd, hh:mm:ss"), f, Brushes.Black, 5, 0);
}
}
}
}

Console.WriteLine("Done.");
Console.ReadLine();
}
}
}


Chris.
-------------
C.R. Timmons Consulting, Inc.
http://www.crtimmonsinc.com/
 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Using System.Drawing for a Custom Font jjbutera@hotmail.com Microsoft ASP .NET 1 9th Jan 2006 09:38 PM
IFont <-> System::Drawing::Font Phil Atkin Microsoft VC .NET 3 24th Jun 2005 02:10 PM
System.Drawing - Font Class =?Utf-8?B?Qm9i?= Microsoft Dot NET Compact Framework 1 27th Apr 2004 12:56 AM
'System.ArithmeticException' in system.drawing.dll, from font constructor Romain TAILLANDIER Microsoft Dot NET Framework 0 17th Nov 2003 01:13 PM
System::Drawing::Font::ToLogFont example needed Bob Microsoft Dot NET Framework Forms 1 3rd Nov 2003 07:25 AM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 10:17 AM.