Freeing memory phobia

  • Thread starter Thread starter Martin Hart - Memory Soft, S.L.
  • Start date Start date
M

Martin Hart - Memory Soft, S.L.

I have a phobia about cleaning up after executing my code. Can someone in
the know help me :-)

-) If I add a delegate handler to a class, do I have to unplug it before
destroying the class for GC to work correctly?

-) Who actually calls Destroy if I implement IDisposable?

-) What is the difference between Destroy() and Destroy(bool) and who calls
each implementation and when?

-) Is it worth setting expired (variables I won't use again in a function)
variables to null to aid GC?

-) Can I or should I aid GC by using 'using' constructs or won't this help
if objects don't implement IDisposable?

Any help would be appreciated.

Regards,
Martin.
 
Martin Hart - Memory Soft said:
I have a phobia about cleaning up after executing my code. Can someone in
the know help me :-)

-) If I add a delegate handler to a class, do I have to unplug it before
destroying the class for GC to work correctly?

If you subscribe to an event, that's a live reference. If the event
lives on beyond the point where the rest of the code has a live
reference to the target of the delegate, the reference in the event
prevents the target from being garbage collected. Usually I find this
isn't a problem, as (IME) the event itself is usually eligible for
garbage collection at the same point as the target of the delegate.
-) Who actually calls Destroy if I implement IDisposable?

Do you mean Dispose? If so, the user of the class should.
-) What is the difference between Destroy() and Destroy(bool) and who calls
each implementation and when?

Again, I take it you mean Dispose. Dispose(bool) is usually a protected
virtual method, called by both the public Dispose() method and the
finalizer, if a finalizer is required.
-) Is it worth setting expired (variables I won't use again in a function)
variables to null to aid GC?

Not generally, no. There are a very few cases where it's appropriate,
but I can't say I've ever run into it in production code.
-) Can I or should I aid GC by using 'using' constructs or won't this help
if objects don't implement IDisposable?

It won't even compile if the type doesn't implement IDisposable.
 
Martin,
-) If I add a delegate handler to a class, do I have to unplug it before
destroying the class for GC to work correctly?

No, GC will still work correcly. But the event provider will keep your
handler object alive as long as the event delegate is there.

-) Who actually calls Destroy if I implement IDisposable?

Dispose should be called by whoever owns the disposable object. That's
usually the same as the creator, but not always.

-) What is the difference between Destroy() and Destroy(bool) and who calls
each implementation and when?

Dispose() calls Dispose(true), and the finalizer may call
Dispose(false). The common implementation is in Dispose(bool).

-) Is it worth setting expired (variables I won't use again in a function)
variables to null to aid GC?

Not local variables, no.

-) Can I or should I aid GC by using 'using' constructs or won't this help
if objects don't implement IDisposable?

using/IDisposable doesn't affect GC in any way. And you can't use
using on classes that don't implement IDisposable.



Mattias
 
Jon:

Thanks for the quick answer.
If you subscribe to an event, that's a live reference. If the event
lives on beyond the point where the rest of the code has a live
reference to the target of the delegate, the reference in the event
prevents the target from being garbage collected. Usually I find this
isn't a problem, as (IME) the event itself is usually eligible for
garbage collection at the same point as the target of the delegate.

Yes, of course I hadn't seen that facet. Only using static handlers would
mess this up, right?
Do you mean Dispose? If so, the user of the class should.

Yes I do. Does WinForms call this internally when the form is destroyed?
Again, I take it you mean Dispose. Dispose(bool) is usually a protected
virtual method, called by both the public Dispose() method and the
finalizer, if a finalizer is required.

Okay so this is not a .NET framework behaviour its a user responsibility?
It won't even compile if the type doesn't implement IDisposable.

You are, of course, right again. Sorry for the confusion.

Regards,
Martin.
 
Mattias:
Dispose() calls Dispose(true), and the finalizer may call
Dispose(false). The common implementation is in Dispose(bool).

So it's a user thing not an integral part of .NET's framework? When I say
user I mean 'developer' as opposed to a protocol to be adhered to, to make
thinks work.

Regards,
Martin.
 
The Dispose(bool) is simply an implementation detail for how IDisposable.Dispose and the finalizer share common clean up code

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Mattias:
Dispose() calls Dispose(true), and the finalizer may call
Dispose(false). The common implementation is in Dispose(bool).

So it's a user thing not an integral part of .NET's framework? When I say
user I mean 'developer' as opposed to a protocol to be adhered to, to make
thinks work.

Regards,
Martin.
 
Martin Hart - Memory Soft said:
Yes, of course I hadn't seen that facet. Only using static handlers would
mess this up, right?

What exactly do you mean by "static handlers"? Delegates where the
target method is static and therefore there's no target object, or
events declared as static?
Yes I do. Does WinForms call this internally when the form is destroyed?

Application.Run certainly does. If you're showing another form, I
*believe* it's up to you to dispose of it, but I don't know for sure.
Okay so this is not a .NET framework behaviour its a user responsibility?

Calling Dispose is a user responsibility; finalizers are "built-in" but
will only be called at an indeterminate time (if at all).
You are, of course, right again. Sorry for the confusion.

No problem.
 
I hope my answer would be clear ;)
-) If I add a delegate handler to a class, do I have to unplug it before
destroying the class for GC to work correctly?
1you don't destroy the instance your self (it's GC responsability), if you
call dispose you will just create problem if the object is still referenced
in a live oject through an event delegate.
yep you need to unplug it to collect it, do that in Dispose() ;).
You do well to see that, many people don't.
-) Who actually calls Destroy if I implement IDisposable?
Dispose() you mean?
it's your responsability!
althought
using(Blabla bla= new Blabla())
statetment;
would call Dispose() automatically for you if it can be.
-) What is the difference between Destroy() and Destroy(bool) and who
calls each implementation and when?
Dispose(bool) is usually called by Dispose().
why do they use such convoluted apporach?
it's a bit subtle and it's related to unmanaged resource, somewhere in the
SDK it's well explained but I can't find it again.

shortly:
- managed memory is automaticall managed!
- however unmanaged resource (typically resource acquire through interop
with win32) are not
- also some classes use some sparse or huge system resource and you want to
have a way to release them explicitely soon
- object are first marked for deletion, then deleted in random order,
therefore you should'nt call method on your managed properties while being
disposed (if dispose as been call from the destructor)

the pattern is the following:
if you have unmanaged resource, release them in Dispose() and ensure dispose
is called by overriding the destructor:
class MyClass : IDisposable
{
IntPtr unmanagedresource;

public MyClass() {}
~MyClass() { Dispose(); } //<=otherwise dispose won;'t be automatically
called!

public void Dispose()
{
GC.UnregisterFinalize(this);
if(unmanagedresource != IntPtr.Zero)
{
FreeUnmanagedResource(unmanagedresource);
unmanagedresource = IntPtr.Zero;
}
}
}

however a problem arise if you've got manage resource as well.
class MyClass : IDisposable
{
IntPtr unmanagedresource;
OtherClass managedresource;

public MyClass() {}
~MyClass() { Dispose(); }

public void Dispose()
{
GC.UnregisterFinalize(this);
if(unmanagedresource != IntPtr.Zero)
{
FreeUnmanagedResource(unmanagedresource);
unmanagedresource = IntPtr.Zero;
}
managedresource.SomeMethod(); // <== potential problem
}
}
the problem is if Dispose() was called by ~MyClass() your managedresource
could have already been freed, which would led to an exception!

hence the following pattern:
class MyClass : IDisposable
{
IntPtr unmanagedresource;
OtherClass managedresource;

public MyClass() {}
~MyClass() { Dispose(false); }
public void Dispose() { Dispose(true); }

protected virtual void Dispose(bool disposing)
{
if(unmanagedresource != IntPtr.Zero)
{
FreeUnmanagedResource(unmanagedresource);
unmanagedresource = IntPtr.Zero;
}
if(disposing)
{
GC.UnregisterFinalize(this);
managedresource.SomeMethod();
}
}
}
-) Is it worth setting expired (variables I won't use again in a function)
variables to null to aid GC? no

-) Can I or should I aid GC by using 'using' constructs or won't this help
if objects don't implement IDisposable?
it helps only with IDisposable
Any help would be appreciated.
you're wellcome
 
Jon:
What exactly do you mean by "static handlers"? Delegates where the
target method is static and therefore there's no target object, or
events declared as static?

Jon, I'm sorry but I wrote the question from memory and once I checked
the code I saw the question was a terminalogical inexactitude (a lie!)

What I have is a 'global' class that handles the KeyDown action for
text controls. This class is created once and then shared between
different forms:

public void Gestionar_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyCode == Keys.Return || e.KeyCode == Keys.Down)
{
System.Windows.Forms.SendKeys.Send("{TAB}");
e.Handled = true;
}
else if(e.KeyCode == Keys.Up)
{
System.Windows.Forms.SendKeys.Send("+{TAB}");
e.Handled = true;
}
}

As this is an application global class, I take it I *must* remove the
handler upon form destruction or I will have assigned pointers,
therefore impeding GC, right?

This also begs a final question... I use 'dangling' variables in several
places. By this I mean, I have code similar to:

new
Auxiliar.EnumTipoNacionalidad().FillEditor(editTipoNacion.Properties);

Here I create a new class to do a specific job, but don't assign
it to any variable. The class just fills the 'editTipoNacion.Properties'
with certain values and can then disappears. Is this GC safe?
Calling Dispose is a user responsibility; finalizers are "built-in" but
will only be called at an indeterminate time (if at all).

Perfect that was the answer I needed, unequivocal and concise :-)

Best regards,
Martin.
 
Richard:

Thanks that clarifies it completely for me.

Regards,
Martin.
 
Lloyd:

Wow, now that's an answer!! I now understand the Dispose(bool)
philosophy and why it exists. Thanks for the time and effort in
responding to my post :-))

Regards,
Martin.
 
Martin Hart - Memory Soft said:
Jon, I'm sorry but I wrote the question from memory and once I checked
the code I saw the question was a terminalogical inexactitude (a lie!)

What I have is a 'global' class that handles the KeyDown action for
text controls. This class is created once and then shared between
different forms:

public void Gestionar_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyCode == Keys.Return || e.KeyCode == Keys.Down)
{
System.Windows.Forms.SendKeys.Send("{TAB}");
e.Handled = true;
}
else if(e.KeyCode == Keys.Up)
{
System.Windows.Forms.SendKeys.Send("+{TAB}");
e.Handled = true;
}
}

As this is an application global class, I take it I *must* remove the
handler upon form destruction or I will have assigned pointers,
therefore impeding GC, right?

Nope. That way round, it's not a problem. The problem usually talked
about is when a form should outlive the event handler's target object -
that's when you need to need to remove the event handler.

Note that your method above could be static, which would remove all
question about what the GC will do.
This also begs a final question... I use 'dangling' variables in several
places. By this I mean, I have code similar to:

new
Auxiliar.EnumTipoNacionalidad().FillEditor(editTipoNacion.Properties);

Here I create a new class to do a specific job, but don't assign
it to any variable. The class just fills the 'editTipoNacion.Properties'
with certain values and can then disappears. Is this GC safe?

Absolutely. If the method doesn't store a reference to "this"
somewhere, the instance will be eligible for collection next time the
GC runs.
Perfect that was the answer I needed, unequivocal and concise :-)

Goodo :)
 
Jon:
Nope. That way round, it's not a problem. The problem usually talked
about is when a form should outlive the event handler's target object -
that's when you need to need to remove the event handler.

I don't doubt you're answer but I can't see why this is *not* a problem :-(
I understand, from your comments, that unreferenced variables are
candidates for GC, but must not be reachable from any other point.

So, if modeless form 'A' is created and a global delegate handler is
added (+=) to a particular control's (owner by form 'A') KeyDown delegate,
when form 'A' is closed, is not the control's delegate still pointing to
the global handler, therefore preventing GC? Obviously not! but I don't
understand why not :-((

Note that your method above could be static, which would remove all
question about what the GC will do.

Hmm, you're right this is probably the best solution.

Once again, I really appreciate the responses and insight,

Regards,
Martin.
 
Martin Hart - Memory Soft said:
I don't doubt you're answer but I can't see why this is *not* a problem :-(
I understand, from your comments, that unreferenced variables are
candidates for GC, but must not be reachable from any other point.

So, if modeless form 'A' is created and a global delegate handler is
added (+=) to a particular control's (owner by form 'A') KeyDown delegate,
when form 'A' is closed, is not the control's delegate still pointing to
the global handler, therefore preventing GC? Obviously not! but I don't
understand why not :-((

A has a reference to the global handler, but the global handler doesn't
have a reference to A. If nothing else has a reference to A either,
there's nothing preventing it from being garbage collected. The
reference in an event goes "from" the container of the event "to" the
targets of the delegates handling the event - there's no link the other
way round.
 
Jon:

Okay, got it at last. Easy once you know how!!!

Coming from 15 years of C++ (and a strict upbringing!) I can't
get my head around not cleaning up after myself ;-)

You make a great teacher Jon, thanks,
Martin.
 
Back
Top