.NET GC Woes & Best Practices

  • Thread starter Thread starter Mario T. Lanza
  • Start date Start date
M

Mario T. Lanza

To my fellow .NET developers,

When .NET came out and I attended one of its launch seminars I was
ecstatic about it's potential. I convinced my employer that his next
enterprise-level application should be developed using the
latest-and-greatest technology--.NET! Now that my application has
reach fruition and we're in the deployment stage MAJOR issues are
becoming apparent esp. dealing with memory leaks.

I was under the impression that the Garbage Collector was a godsend--a
magical force who would deal with all my memory management concerns so
that I could be freed to work on the more important issues dealing
with business logic. That assumption was far from true.

Now before I elaborate, let me say this... I realize that every major
undertaking in the programming world is bound to have its bugs. I
myself have never produced anything beyond the simplest of
applications that were without bugs. Therefore, I expect no
perfection from the .NET designers and I still believe largely in
..NET's potential and direction. It's just that I have been riddled
with memory leaks that I never had in the VB6 world. Now that I have
witnessed the power of GC, I'd rather regress to managing my own clean
up.

MY ISSUES WITH GARBAGE COLLECTION:

1. Whether or not Microsoft wants to admit it, the world of
programming is so massive that most programmers cannot be expected to
grasp all the high-level ins and outs necessary for developing
superior apps. I though GC was designed with this in mind; however,
as I read all the posts regarding it I can see that there is an
overwhelming number of confused developers who are unsure about it.
Back when I set my objects to Nothing once I finished using them,
things were easy.

2. Hanging references are rampant. Say you create an object that
contains other objects. When that object falls out of scope but has
inner-objects that go on living, although you would expect it to die,
it lives. One very common example of this arises when you create a
form and assign event handlers to the various events, but do not
remove those handlers when the form is closed. The dead form
reference exists in limbo never to be reclaimed. From a simplistic
standpoint, should GC be intelligent enough to dispose of all inner
objects when the parent object reference falls out of scope? I mean,
if it's obvious that I can never make reference to the closed form
again and all the inner objects are ONLY referenced by the form
itself--i.e. they are complete self-contained--why bother retaining it
in memory!?

3. Because of .NET it is almost a requirement that developers purchase
a memory profiling tool. If I hadn't I wouldn't have stood a chance
at eliminating my memory leaks. At present, with the tool, I have
only just begun plugging all the leaks.

4. As more and more .NET issues emerge for me, it would be nice to
have a specific Microsoft URL that has a .NET priority list of issues.
Knowing what MS was working on would help put me at ease and make me
eagerly anticipate the next release.


GARBAGE COLLECTION CONFUSIONS:

Although GC was intended to make my life easier, I have had to do
volumes of research that lead to tons of questions and some answers.
Eventually, I decided that learning from the posters on these
newsgroups had limited value--everyone kept speaking definitively on
the topic only to be contradicted by someone else who was in turn
contradicted again.

Here are some of the questions I asked...

It seems that there are several ways of cleaning up objects--use
deconstructors, implement the IDispose interface and call Dispose (or
use a using statement), set the object to null, and override the
finalizer method. (I am still uncertain as to whether the finalizer
and the deconstructor are one in the same.)

Q1: What is the train of thought I should use to know how to properly
clean up objects? Call Dispose if it exists, nullify it, or both?

Q2: Should I bother nullifying an object that is about to fall out of
scope or does GC clean up nullified objects and out-of-scope objects
the same way? (I'm guessing "yes".)

Q3: If I declare a type and instantiate an object against it is it
important to nullify it before I reuse it to instantiate another
object?

private void Show2Dialogs()
{
MyForm frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = null;
frm = new MyForm(); //instance 2
frm.ShowDialog();
}

vs.

private void Show2Dialogs()
{
MyForm frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = new MyForm(); //instance 2 -- is instance 1 garbage
collected?
frm.ShowDialog();
}

Q4: How does the scope of the type impact this? What if the type is
static or belongs to a static class?

MyForm frm = null;
private void Show2Dialogs()
{
frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = null;
frm = new MyForm(); //instance 2
frm.ShowDialog();
}

vs.

MyForm frm = null;
private void Show2Dialogs()
{
frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = new MyForm(); //instance 2 -- is instance 1 garbage
collected
frm.ShowDialog();
}

Q5: What are the GC ramifications using unassigned object references
directly?

new ToolTip().SetToolTip(MyButton, "Click me to continue...");

(Tool tips are graphical objects. Is there a difference on doing
the same with non-graphical objects?)

new MyObject().DoSomething(); //obviously a static method might be
better

Q6: From a design standpoint when should I use Dispose or
destructors/finalizers?

Here's what I think I've learned...

Dispose:
Use ONLY when your class deals with unmanaged resources.

Destructors:
Avoid them as there is no way to be sure when the GC will call them.
GC will handle the details for destroying an object's managed
resources without your help.

Q7: Even when I explicitly Dispose an object is it still a good idea
to nullify it?

I would guess "yes". The whole idea of checking at the top of every
method to see whether the object has been disposed makes for ugly code
and seems problematic--what if the programmer forgets to code the
check to determine whether the object has been disposed before
attempting to execute the method's code? By nullifying the object,
this becomes a non-issue.

Q8: Has anyone developed some general suggestions (perhaps a best
practices checklist) on designing for GC?

Q9: Any general suggestions (or a best practices checklist) for
avoiding memory leaks?

e.g. Always remove all event handlers in your disposed objects.

Q10: Regarding removing all event handlers in non-form objects... do
it in a Dispose method or in the deconstructor? Pros/cons of each? I
read some recommendations that event handlers should be removed when a
form is Disposed/Closed, yet in the Windows Form-generated code for
such events as button clicks, there is no attempt to unregister the
event handler. Why is that?

Well, that's more than enough for now. I'm just baffled that this
thing called Garbage Collection--which is supposed to ease our
burden--has done nothing but increase our workload as developers.

I am truly thankful for anyone who takes the time to offer any
feedback. I've been troubleshooting my current project's memory
issues for months (tons of hours!). I've even brought in an outside
contractor to help with the issue. His advice helped and reduced the
memory-leaks, but did not solve the issue.

Mario T. Lanza
Clarity Information Architecture, Inc.
 
Mario T. Lanza said:
2. Hanging references are rampant. Say you create an object that
contains other objects. When that object falls out of scope but has
inner-objects that go on living, although you would expect it to die,
it lives. One very common example of this arises when you create a
form and assign event handlers to the various events, but do not
remove those handlers when the form is closed. The dead form
reference exists in limbo never to be reclaimed. From a simplistic
standpoint, should GC be intelligent enough to dispose of all inner
objects when the parent object reference falls out of scope? I mean,
if it's obvious that I can never make reference to the closed form
again and all the inner objects are ONLY referenced by the form
itself--i.e. they are complete self-contained--why bother retaining it
in memory!?

If the form itself isn't referenced anywhere else, then the event
handlers *will* be garbage collected. The problem arises when the form
is still referenced somewhere even though it has been closed.
It seems that there are several ways of cleaning up objects--use
deconstructors, implement the IDispose interface and call Dispose (or
use a using statement), set the object to null, and override the
finalizer method. (I am still uncertain as to whether the finalizer
and the deconstructor are one in the same.)

I haven't heard of deconstructors - do you mean destructors? If so,
they're somewhat different in terms of when they're expected to be
called (destructors, at least in normal C++, are called
deterministically; finalizers are called when the GC sees fit).
Q1: What is the train of thought I should use to know how to properly
clean up objects? Call Dispose if it exists, nullify it, or both?

Call Dispose if the class implements IDisposable. There's no need to
set a variable to null if either it's a local variable which isn't used
later in the method or if it's an instance variable and the whole
object is about to become eligible for GC.
Q2: Should I bother nullifying an object that is about to fall out of
scope or does GC clean up nullified objects and out-of-scope objects
the same way? (I'm guessing "yes".)

Which are you guessing "yes" to? There's (generally) no need to set a
variable to null. Note that you're not "nullifying an object" - that
doesn't actually mean anything. You're not doing *anything* to the
object in question, just changing the value of a variable which
previously referred to the object.
Q3: If I declare a type and instantiate an object against it is it
important to nullify it before I reuse it to instantiate another
object?
No.

Q4: How does the scope of the type impact this? What if the type is
static or belongs to a static class?

Again, terminology is important here - types aren't static, variables
are. An instance variable doesn't cause the GC to hang on to an object
when the instance itself is eligible for garbage collection. Static
variables, however, live as long as the AppDomain does - so if you have
a static variable which refers to some object which is no longer really
needed, setting that variable to null *would* help. I rarely find this
is the case though.
Q5: What are the GC ramifications using unassigned object references
directly?

new ToolTip().SetToolTip(MyButton, "Click me to continue...");

Well, it really depends what else happens with the reference to that
new object. If it's not retained by anything, it'll be eligible for
garbage collection.
(Tool tips are graphical objects. Is there a difference on doing
the same with non-graphical objects?)

Only in terms of whether or not it implements IDisposable. Many
graphical classes do, and then they should be disposed appropriately -
in the same way that some non-graphical classes do. There's nothing
*really* special about it being a graphical object.
new MyObject().DoSomething(); //obviously a static method might be
better

It might be, it might not be - it depends on what DoSomething does.
Q6: From a design standpoint when should I use Dispose or
destructors/finalizers?
Here's what I think I've learned...

Dispose:
Use ONLY when your class deals with unmanaged resources.
Yes.

Destructors:
Avoid them as there is no way to be sure when the GC will call them.
GC will handle the details for destroying an object's managed
resources without your help.

I'd actually follow the MS guidelines here, and *usually* provide a
finalizer (not a destructor) when I provide a Dispose method.
Q7: Even when I explicitly Dispose an object is it still a good idea
to nullify it?

I would guess "yes".

Nope - see above. There's generally no need to set variables to null,
with a few exceptions (basically when the variable is available longer
than you want the object to be).

Note that with the C# "using" construct (which is usually the way you
should deal with instances of classes which implement IDisposable) the
variable goes out of scope at the end of the using construct anyway.
The whole idea of checking at the top of every
method to see whether the object has been disposed makes for ugly code
and seems problematic--what if the programmer forgets to code the
check to determine whether the object has been disposed before
attempting to execute the method's code? By nullifying the object,
this becomes a non-issue.

I've never seen this idea of checking at the top of every method - why
on earth would I do that? I'm really not following you on this one.
Q8: Has anyone developed some general suggestions (perhaps a best
practices checklist) on designing for GC?

Things follow quite naturally when you understand what it does. I can
thoroughly recommend reading the GC chapter in Jeffrey Richter's
C#/.NET book, for instance.
Q9: Any general suggestions (or a best practices checklist) for
avoiding memory leaks?

e.g. Always remove all event handlers in your disposed objects.

You only need to do that if the object itself isn't going to be
eligible for garbage collection anyway.
Q10: Regarding removing all event handlers in non-form objects... do
it in a Dispose method or in the deconstructor? Pros/cons of each? I
read some recommendations that event handlers should be removed when a
form is Disposed/Closed, yet in the Windows Form-generated code for
such events as button clicks, there is no attempt to unregister the
event handler. Why is that?

Because it's usually not necessary - see above.
Well, that's more than enough for now. I'm just baffled that this
thing called Garbage Collection--which is supposed to ease our
burden--has done nothing but increase our workload as developers.

Only because I think you don't understand it very well - it really
*does* ease the burden, hugely!
 
Mario said:
To my fellow .NET developers,

When .NET came out and I attended one of its launch seminars I was
ecstatic about it's potential. I convinced my employer that his next
enterprise-level application should be developed using the
latest-and-greatest technology--.NET! Now that my application has
reach fruition and we're in the deployment stage MAJOR issues are
becoming apparent esp. dealing with memory leaks.

I was under the impression that the Garbage Collector was a godsend--a
magical force who would deal with all my memory management concerns so
that I could be freed to work on the more important issues dealing
with business logic. That assumption was far from true.

Now before I elaborate, let me say this... I realize that every major
undertaking in the programming world is bound to have its bugs. I
myself have never produced anything beyond the simplest of
applications that were without bugs. Therefore, I expect no
perfection from the .NET designers and I still believe largely in
.NET's potential and direction. It's just that I have been riddled
with memory leaks that I never had in the VB6 world. Now that I have
witnessed the power of GC, I'd rather regress to managing my own clean
up.

MY ISSUES WITH GARBAGE COLLECTION:

1. Whether or not Microsoft wants to admit it, the world of
programming is so massive that most programmers cannot be expected to
grasp all the high-level ins and outs necessary for developing
superior apps. I though GC was designed with this in mind; however,
as I read all the posts regarding it I can see that there is an
overwhelming number of confused developers who are unsure about it.
Back when I set my objects to Nothing once I finished using them,
things were easy.

2. Hanging references are rampant. Say you create an object that
contains other objects. When that object falls out of scope but has
inner-objects that go on living, although you would expect it to die,
it lives. One very common example of this arises when you create a
form and assign event handlers to the various events, but do not
remove those handlers when the form is closed. The dead form
reference exists in limbo never to be reclaimed. From a simplistic
standpoint, should GC be intelligent enough to dispose of all inner
objects when the parent object reference falls out of scope? I mean,
if it's obvious that I can never make reference to the closed form
again and all the inner objects are ONLY referenced by the form
itself--i.e. they are complete self-contained--why bother retaining it
in memory!?

3. Because of .NET it is almost a requirement that developers purchase
a memory profiling tool. If I hadn't I wouldn't have stood a chance
at eliminating my memory leaks. At present, with the tool, I have
only just begun plugging all the leaks.

4. As more and more .NET issues emerge for me, it would be nice to
have a specific Microsoft URL that has a .NET priority list of issues.
Knowing what MS was working on would help put me at ease and make me
eagerly anticipate the next release.


GARBAGE COLLECTION CONFUSIONS:

Although GC was intended to make my life easier, I have had to do
volumes of research that lead to tons of questions and some answers.
Eventually, I decided that learning from the posters on these
newsgroups had limited value--everyone kept speaking definitively on
the topic only to be contradicted by someone else who was in turn
contradicted again.

Here are some of the questions I asked...

It seems that there are several ways of cleaning up objects--use
deconstructors, implement the IDispose interface and call Dispose (or
use a using statement), set the object to null, and override the
finalizer method. (I am still uncertain as to whether the finalizer
and the deconstructor are one in the same.)

Q1: What is the train of thought I should use to know how to properly
clean up objects? Call Dispose if it exists, nullify it, or both?

Dispose() is interesting. If you're worried about memory conservation,
ALWAYS call it before it goes out of scope. The GC is
non-deterministic, in that you don't know **when** the memory will get
freed up. The Dipose() pattern (implemented on the Component) class),
is a way to get around this. Within it's Dispose, a call will free up
anything it's using.
Q2: Should I bother nullifying an object that is about to fall out of
scope or does GC clean up nullified objects and out-of-scope objects
the same way? (I'm guessing "yes".)

Same as above really, just setting to null doesn't immediately do
anything. Internally, it sets to "I'm ready to be deleted" -- you don't
know **when** the GC will kick on.
Q3: If I declare a type and instantiate an object against it is it
important to nullify it before I reuse it to instantiate another
object?

private void Show2Dialogs()
{
MyForm frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = null;
frm = new MyForm(); //instance 2
frm.ShowDialog();
}

vs.

private void Show2Dialogs()
{
MyForm frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = new MyForm(); //instance 2 -- is instance 1 garbage
collected?
frm.ShowDialog();
}

As above, it doesn't make a difference.
Q4: How does the scope of the type impact this? What if the type is
static or belongs to a static class?

MyForm frm = null;
private void Show2Dialogs()
{
frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = null;
frm = new MyForm(); //instance 2
frm.ShowDialog();
}

vs.

MyForm frm = null;
private void Show2Dialogs()
{
frm = new MyForm(); //instance 1
frm.ShowDialog();
frm = new MyForm(); //instance 2 -- is instance 1 garbage
collected
frm.ShowDialog();
}

No difference, same thing. But, in both cases -- you're not freeing the
Form reference up, you need to call that Dispose().
Q5: What are the GC ramifications using unassigned object references
directly?

new ToolTip().SetToolTip(MyButton, "Click me to continue...");

(Tool tips are graphical objects. Is there a difference on doing
the same with non-graphical objects?)

new MyObject().DoSomething(); //obviously a static method might be
better

Q6: From a design standpoint when should I use Dispose or
destructors/finalizers?

Here's what I think I've learned...

Dispose:
Use ONLY when your class deals with unmanaged resources.

Nope, call it everytime you can.
Destructors:
Avoid them as there is no way to be sure when the GC will call them.
GC will handle the details for destroying an object's managed
resources without your help.

Exactly, the Finalize/Destructor method is bad. You don't know **when**
it's going to be called. In a small app, it doesn't matter -- in a
large app that hangs around for a while, it's REALLY important.
Q7: Even when I explicitly Dispose an object is it still a good idea
to nullify it?

I would guess "yes". The whole idea of checking at the top of every
method to see whether the object has been disposed makes for ugly code
and seems problematic--what if the programmer forgets to code the
check to determine whether the object has been disposed before
attempting to execute the method's code? By nullifying the object,
this becomes a non-issue.

Dispose() is enough.
 
Mario T. Lanza wrote:

I should point out . . .

The reason the Dispose() pattern is better than Finalize/Destructor, is
that when you call Dispose, you tell that object to free up anything
it's using. This ripples on down, to all 'known' Child objects (any
object implementing Dispose should implement IDispose). By freeing up
the objects, you're giving the GC much more information.

Thus, when it's periodically scanning, passing memory through the
lifecycle phases, you stand a better chance of things getting released.

Also, Dispose(), as you point out, is ESSENTIAL for the freeing up of
Win32 resources. If it was left to the Finalize method, you could
easily run out of resources if you allocate them a lot.

One note on memory usage . . .

In a .NET app, you can merrily see the phys/virtual memory allocation
rising. This isn't necessarily anything to worry about. As I said, the
GC is non-deterministic. There are, however, a few ways to force it.
As an experiment/test, just minimize the app, you'll see the physical
reduce. Also, when the machine gets low on RAM, the kernel issues a "I
need more RAM!" -- this actually forces the GC to kick on and release
memory allocated within the CLR.

So . . . EVEN THOUGH THE MEMORY COUNT RISES, THIS DOESN'T MEAN IT'S NOT
RELEASING ANYTHING. Releasing memory is slow, it ONLY DOES IT WHEN IT
HAS TO.

Incidentally, Java's GC works in a very similar way.

Hope this helps, hopefully someone from MS will comment.

Sean
 
Jon Skeet said:
I've never seen this idea of checking at the top of every method - why
on earth would I do that? I'm really not following you on this one.

I think he's referring to the ObjectDisposedException. And he's right, the
implementing class that implements IDisposable should indeed check at the
top of every routine and throw it. That is, unless the object has been
resurrected. Ugh.

http://msdn.microsoft.com/library/d...rfsystemobjectdisposedexceptionclasstopic.asp

-- Alan
 
Alan Pretre said:
I think he's referring to the ObjectDisposedException. And he's right, the
implementing class that implements IDisposable should indeed check at the
top of every routine and throw it. That is, unless the object has been
resurrected. Ugh.

Yes, that would make sense - except that "nullifying the object"
wouldn't help.

Fortunately of course, writing classes which implement IDisposable is a
rare occurrence (in my experience, anyway).
 
Thank you very much for taking the time to respond. Your insight was
most helpful. I have been reading about garbage collection for almost
a full workday trying to gain a better understanding of it. The main
reason I have found it baffling is that my enterprise-level
application--the one I wrote to be deployed at 50+ stores--is leaking
memory. I have been using the SciTech .NET Memory Profiler to
determine what objects are hanging around. It's obvious that I don't
fully understand the GC as I still have hanging references. The main
symptom of the leak is that the app begins to slow down after about 50
transactions and the user must restart the app.

Within the app I force garbage collection after each transaction.
Doing this greatly improved the performance. Prior to doing this, the
app began to slow down after 15 transactions. Before and after
forcing collection, I log the Total Memory used by the app.

long gcbefore = GC.GetTotalMemory(false);
long gcafter = GC.GetTotalMemory(true);
App.LogMessage("GC: Before = " + gcbefore.ToString() + "; After = "
+ gcafter.ToString());

(Oddly enough GC.GetTotalMemory(true) produced better results than
GC.Collect(). I don't know why!? I would have thought GC.Collect()
sufficient.)

I can see, although I do reclaim memory after each forced collection,
that memory is still on the rise. I can also confim using the Memory
Profiler that more objects are created than destroyed when I
repetitively enter transactions. I am trying to do everything I can
to alleviate all leaks so that the application can run all day long
without the teller having to restart it.
I haven't heard of deconstructors - do you mean destructors?

Yes, destructors, sorry. By the way are destructors different from
finalizers in C#?
Which are you guessing "yes" to? There's (generally) no need to set a
variable to null. Note that you're not "nullifying an object" - that
doesn't actually mean anything. You're not doing *anything* to the
object in question, just changing the value of a variable which
previously referred to the object.

Yes, of course. I meant setting the reference to null.
Well, it really depends what else happens with the reference to that
new object. If it's not retained by anything, it'll be eligible for
garbage collection.

I think you are misunderstanding my example. I am instantiating the
tooltip without assigning it to a reference variable and calling it's
method directly. As soon as the line has been exectued, nothing
references the tool tip.
Only in terms of whether or not it implements IDisposable. Many
graphical classes do, and then they should be disposed appropriately -
in the same way that some non-graphical classes do. There's nothing
*really* special about it being a graphical object.

I read somewhere that I should make a special effort to call Dispose
on graphical objects.

Can you clarify what unmanaged resources are? I've heard db
connections and files, etc. What is confusing is that the .NET
framework allows me to reference the database using SqlConnection and
files using StreamReader. Are these considered unmanaged? I would
have thought no because they are available under the .NET framework.
Perhaps a few examples of some clean-up code I might see in a Dispose
method to release "unmanaged resources."
I've never seen this idea of checking at the top of every method - why
on earth would I do that? I'm really not following you on this one.

The clarification provided by the other poster was correct.
Only because I think you don't understand it very well - it really
*does* ease the burden, hugely!

Yes, I don't understand it very well. I mean I could give a
reasonably accurate text book exposition on what I've read about GC.
However, I am still *baffled* as to why my app eats up memory over
time.

As I am a one-man operation, I called several consulting firms looking
to hire a temporary consultant with more experience than myself. I
did greatly appreciate his help, but despite the progress I made with
his added insight, the problem was not totally resolved.

Thanks again for your time.
Mario T. Lanza
Clarity Information Architecture, Inc.
 
Mario T. Lanza said:
Thank you very much for taking the time to respond. Your insight was
most helpful. I have been reading about garbage collection for almost
a full workday trying to gain a better understanding of it. The main
reason I have found it baffling is that my enterprise-level
application--the one I wrote to be deployed at 50+ stores--is leaking
memory. I have been using the SciTech .NET Memory Profiler to
determine what objects are hanging around. It's obvious that I don't
fully understand the GC as I still have hanging references. The main
symptom of the leak is that the app begins to slow down after about 50
transactions and the user must restart the app.

<snip>

It's worrying that you force garbage collection in the first place - this
is very rarely useful. However, without closer inspection of your app
it's hard to say where you've got dangling references. Do you have unit
tests that you can run to work out which *part* of the app is leaking?
Do you know which types of objects are leaking?
(Oddly enough GC.GetTotalMemory(true) produced better results than
GC.Collect(). I don't know why!? I would have thought GC.Collect()
sufficient.)

Not sure, to be honest - it's possible that GC.GetTotalMemory(true)
runs the garbage collection and waits for pending finalizers, then runs
garbage collection again, although that would surprise me.
Yes, destructors, sorry. By the way are destructors different from
finalizers in C#?

You don't have destructors at all in C# :)

I suspect they didn't call them destructors because that would give the
wrong impression to those who expect destructors to be called
deterministically.
I think you are misunderstanding my example. I am instantiating the
tooltip without assigning it to a reference variable and calling it's
method directly. As soon as the line has been exectued, nothing
references the tool tip.

Then it will be eligible for garbage collection. My point was that some
classes with the above type of code may register the instance somewhere
either during construction or during the method call. For instance,
SetToolTip *could* register the ToolTip itself with the button being
referenced. In practice, I believe it only registers the text itself,
but it certainly *could* register the ToolTip itself.
I read somewhere that I should make a special effort to call Dispose
on graphical objects.

You should make a special effort to call Dispose on everything that
implements IDisposable, IMO.
Can you clarify what unmanaged resources are? I've heard db
connections and files, etc. What is confusing is that the .NET
framework allows me to reference the database using SqlConnection and
files using StreamReader. Are these considered unmanaged? I would
have thought no because they are available under the .NET framework.
Perhaps a few examples of some clean-up code I might see in a Dispose
method to release "unmanaged resources."

StreamReader and SqlConnection themselves aren't unmanaged - but they
may *contain* unmanaged resources. If I had a class which contained a
StreamReader, I'd probably implement IDisposable but *not* implement a
finalizer - if things are being garbage collected, then the
StreamReader can look after freeing up anything itself. My Dispose
method would call Dispose on the StreamReader though.

Now, direct unmanaged resources would be things like handles - which
you're unlikely to need to use directly very often. An example where I
did use them directly was when I was writing a RegistryKey class for
the Compact Framework. The registry key had an associated handle (the
..NET registry classes don't exist in the Compact Framework) so I
implemented IDisposable and a finalizer to make sure that the handle
would be freed whatever happened.
The clarification provided by the other poster was correct.

Right - in that case, "nullifying the object" doesn't help you at all -
you still need to check at the start of every method in the class which
implements IDisposable, because the variable you've set to null might
not be the only reference to the object. Yes, implementing IDisposable
is a bit of a pain (there have been discussions about how it could be
improved) - but fortunately, you rarely need to do it yourself.
Yes, I don't understand it very well. I mean I could give a
reasonably accurate text book exposition on what I've read about GC.
However, I am still *baffled* as to why my app eats up memory over
time.

As I am a one-man operation, I called several consulting firms looking
to hire a temporary consultant with more experience than myself. I
did greatly appreciate his help, but despite the progress I made with
his added insight, the problem was not totally resolved.

It does sound like unit tests are the way forward - if you can run just
half your code, repeatedly, and see whether that leaks, then run the
other half, etc, you should be able to narrow it down quickly.
 
Jon said:
<snip>

It's worrying that you force garbage collection in the first place - this
is very rarely useful. However, without closer inspection of your app
it's hard to say where you've got dangling references. Do you have unit
tests that you can run to work out which *part* of the app is leaking?
Do you know which types of objects are leaking?




Not sure, to be honest - it's possible that GC.GetTotalMemory(true)
runs the garbage collection and waits for pending finalizers, then runs
garbage collection again, although that would surprise me.




You don't have destructors at all in C# :)

I suspect they didn't call them destructors because that would give the
wrong impression to those who expect destructors to be called
deterministically.




Then it will be eligible for garbage collection. My point was that some
classes with the above type of code may register the instance somewhere
either during construction or during the method call. For instance,
SetToolTip *could* register the ToolTip itself with the button being
referenced. In practice, I believe it only registers the text itself,
but it certainly *could* register the ToolTip itself.




You should make a special effort to call Dispose on everything that
implements IDisposable, IMO.




StreamReader and SqlConnection themselves aren't unmanaged - but they
may *contain* unmanaged resources. If I had a class which contained a
StreamReader, I'd probably implement IDisposable but *not* implement a
finalizer - if things are being garbage collected, then the
StreamReader can look after freeing up anything itself. My Dispose
method would call Dispose on the StreamReader though.

Now, direct unmanaged resources would be things like handles - which
you're unlikely to need to use directly very often. An example where I
did use them directly was when I was writing a RegistryKey class for
the Compact Framework. The registry key had an associated handle (the
.NET registry classes don't exist in the Compact Framework) so I
implemented IDisposable and a finalizer to make sure that the handle
would be freed whatever happened.




Right - in that case, "nullifying the object" doesn't help you at all -
you still need to check at the start of every method in the class which
implements IDisposable, because the variable you've set to null might
not be the only reference to the object. Yes, implementing IDisposable
is a bit of a pain (there have been discussions about how it could be
improved) - but fortunately, you rarely need to do it yourself.




It does sound like unit tests are the way forward - if you can run just
half your code, repeatedly, and see whether that leaks, then run the
other half, etc, you should be able to narrow it down quickly.
Not strictly true, you do have Destructors in C#. However, as Jon
points out, they're not 'real'. Although you can specify the destructor
in C# (~), at compilation time, it gets mapped to the Finalize method.
If you don't explicity give a Finalize method, it will.

S
 
For clarification: Regarding GC.GetTotalMemory(true), it checks all
references in the object graph regardless of generation. It is similar to
GC.Collect(GC.MaxGeneration) however it also returns the amount of memory
still in use after Garbage Collection runs.

Remember GC.Collect() ONLY checks generation 0 objects, that is only
collects
objects that have not survived a Collection attempt previously. This
prevents
the GC process from having to check static(shared) or other long term object
references every time GC runs.

That being said, I think you are missing the point on Garbage Collection,
Mario. Those are not memory leaks, if the system needs memory the CRL will
give it up. But It will wait to release it until then. As another poster
mentioned, releasing memory is an expensive prospect.

Good Luck,

Ross Porter, MCT
 
Sean J Donovan said:
Not strictly true, you do have Destructors in C#. However, as Jon
points out, they're not 'real'. Although you can specify the destructor
in C# (~), at compilation time, it gets mapped to the Finalize method.
If you don't explicity give a Finalize method, it will.

Apologies, you're right. I had thought they'd been "renamed" in C# and
that the word destructor didn't occur in the C# specification. I'm very
wrong :(
 
Ross Porter said:
For clarification: Regarding GC.GetTotalMemory(true), it checks all
references in the object graph regardless of generation. It is similar to
GC.Collect(GC.MaxGeneration) however it also returns the amount of memory
still in use after Garbage Collection runs.

Remember GC.Collect() ONLY checks generation 0 objects, that is only
collects objects that have not survived a Collection attempt previously.
This prevents the GC process from having to check static(shared) or other
long term object references every time GC runs.

No - GC.Collect forces garbage collection of all generations - at least
according to the docs.
That being said, I think you are missing the point on Garbage Collection,
Mario. Those are not memory leaks, if the system needs memory the CRL will
give it up. But It will wait to release it until then. As another poster
mentioned, releasing memory is an expensive prospect.

No, it really *does* sound like there's a memory leak here - if the
user is having to restart the app, there's a problem. It *may* not be
the case, but I haven't seen any non-leak situations where it's slowed
down over time in the way described.
 
Dispose:

No. Best to implement IDispose for every class that has an exclusive
reference to (ownership of) any other IDispose instance. Best to call
Dispose on everything that implements IDispose, for critical code (where
performance matters).
I'd actually follow the MS guidelines here, and *usually* provide a
finalizer (not a destructor) when I provide a Dispose method.

Never provide a finalizer unless you are implementing a wrapper around an
unmanaged resource. For more details:
http://www.gotdotnet.com/team/libraries/whitepapers/resourcemanagement/resourcemanagement.aspx

This is the best MS resource for these questions.

Regards,
Frank Hileman
Prodige Software Corporation
 
<snip>

Just to say, I agree absolutely - I was expressing myself badly and/or
not thinking properly.
 
Jon,

From what I have been able to accertain, you are, of course, correct as
usual. It is only when GC runs automatically that it collects only
generation zero and then proceedes up the generations when necessary. I was
mistakenly interpreting "invoked" to impy "GC.Collect", when in fact the
resource I was using (quote below) was referring to the framework
invocation.

<QUOTE>
When garbage collection is invoked to free heap space, its
performance is
improved because it only compacts the section of the
managed heap that
contains generation 0 objects.

Typically, the newer an object is, the shorter its
lifetime will be.
Therefore,sufficient space is usually freed when
generation 0 is compacted. If
sufficient space cannot be obtained when generation 0 is
compacted, garbage
collection will compact the older generations.
(MOC, Course 2349, Module 9, page 42)
</QUOTE>

I will admit I was being a little over adamant in my statement regarding
leaks. And I must have missed the statement in Mario's original post that
users were having to restart the app. But, in my experience the majority of
my clients complaints of memory leaks result from a misunderstanding of GC,
especially the quote above. My strong suspission in this case is: All
components are not being explicitly destructed(disposed) and those wich have
finalizers are hanging around too long. Another possiblitlity, although it
sounds remote to me, could be component variables in an unreachable object
are being instanciated in the finialization process or some form of
resurrection is taking place in finalization.

I have too many enterprise apps running to believe that the Framework itself
or, more specifically, GC is causing the memory leaks. I just try to make
certain that I follow the recommended practices from the Microsoft:

o If a Framework class provides a Dispose method, USE IT.
o If you implement a finilzer/destructor always implement IDisposable
o Ensure that Dispose calls GC.SupressFinialize()

The last seems to be the most prevelantly ignored. If you do not surpress
finalize, your object remains in the finilization queue and its finilizer
must be called, meaning it survives the first round of Garbage Collection.
 
Ross Porter said:
I have too many enterprise apps running to believe that the Framework itself
or, more specifically, GC is causing the memory leaks.

Absolutely agreed. I've seen some cases where the framework *can* cause
leaks (regular expressions being the most obvious example I can think
of) but in 99% of cases I'm sure it's in the client code.
I just try to make
certain that I follow the recommended practices from the Microsoft:

o If a Framework class provides a Dispose method, USE IT.
o If you implement a finilzer/destructor always implement IDisposable
o Ensure that Dispose calls GC.SupressFinialize()

The last seems to be the most prevelantly ignored. If you do not surpress
finalize, your object remains in the finilization queue and its finilizer
must be called, meaning it survives the first round of Garbage Collection.

Yup. I believe that actually, writing classes which implement
IDisposable should be fairly rare - I certainly haven't had to do it
often, and don't expect to. I very, very rarely deal with unmanaged
resources directly, and when I deal with classes which implement
IDisposable themselves, I rarely keep instances around as anything
other than local variables which are quickly disposed themselves.

(This is not to say I can't see the times when it *is* necessary, just
that I think they're rare.)
 
Back
Top