Barry Anderberg <ba******@yahoo.com> wrote in
news:#9**************@TK2MSFTNGP11.phx.gbl:
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/