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.
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.