Home All Groups Group Topic Archive Search About

SuppressFinalize in Dispose confusion

Author
17 Mar 2006 5:52 PM
uncaged
I'm confused about using SuppressFinalize in Dispose.

My class has a Socket member, so FxCop complained that my class needs to
implement IDispose.

Documentation says that either Dispose or the finalizer (destructor?) get
called, but never both.  Is that because the examples have SuppressFinalize
being called in Dispose?

In my attempt to follow the examples, I've got a destructor that calls
Dispose(false), a Dispose() that calls Dispose(true) and
GC.SupressFinalize(this), and a Dispose(bool) that looks like:

protected virtual void Dispose( Boolean disposing)
{
    if (! disposed)
    {
        if (disposing)
        {
            if (listenerSocket != null)
            {
                listenerSocket.Close();
                listenerSocket = null;
            }
        }
        disposed = true;
    }
}

First of all, is this right?

Next, I'm confused about SuppressFinalize being called in Dispose().  My
class has other object members.  Does my Dispose(bool) need to set them all
to null in order for them to get cleaned up by garbage collection?  If not,
when are they available for collection?

I'm also confused about the examples.  In the SuppressFinalize documentation
(ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/M_System_GC_SuppressFinalize_1_b4c5a2da.htm),
for example, in the Dispose(bool disposing) function, it says to dispose of
managed resources only if disposing is true, but to dispose of unmanaged
resource regardless of the value of disposing.  Socket is managed, but isn't
it IDisposable because it manipulates an unmanaged resource?  So should I
call Socket's Close only if disposing is true, or regardless?  By the way,
I'm supposed to call Close, right?  I thought I was supposed to call Socket's
Dispose, but that's protected.

Thanks.

Author
17 Mar 2006 6:13 PM
uncaged
I also see that FxCop says:

    If the type does not own any unmanaged resources, do not implement a
finalizer on it.

This goes to my question about Socket.  It's a managed type, but isn't the
reason it's IDisposable because it contains an unmanaged type?  So, should my
class that contains a Socket member have a destructor (that calls
Dispose(false)) or not?

Thanks
Author
17 Mar 2006 7:36 PM
Jon Skeet [C# MVP]
uncaged <unca***@discussions.microsoft.com> wrote:
> I also see that FxCop says:
>
>     If the type does not own any unmanaged resources, do not implement a
> finalizer on it.
>
> This goes to my question about Socket.  It's a managed type, but isn't the
> reason it's IDisposable because it contains an unmanaged type?  So, should my
> class that contains a Socket member have a destructor (that calls
> Dispose(false)) or not?

Nope. Unless you hold onto the resources *directly*, you don't need to
have a finalizer. Instead, Socket (or whatever it uses to hold onto the
handle) should have the finalizer.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
18 Mar 2006 4:03 AM
uncaged
Thanks !

Show quote
"Jon Skeet [C# MVP]" wrote:

> uncaged <unca***@discussions.microsoft.com> wrote:
> > I also see that FxCop says:
> >
> >     If the type does not own any unmanaged resources, do not implement a
> > finalizer on it.
> >
> > This goes to my question about Socket.  It's a managed type, but isn't the
> > reason it's IDisposable because it contains an unmanaged type?  So, should my
> > class that contains a Socket member have a destructor (that calls
> > Dispose(false)) or not?
>
> Nope. Unless you hold onto the resources *directly*, you don't need to
> have a finalizer. Instead, Socket (or whatever it uses to hold onto the
> handle) should have the finalizer.
>
> --
> Jon Skeet - <sk***@pobox.com>
> http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
> If replying to the group, please do not mail me too
>
Author
17 Mar 2006 7:15 PM
Brian Gideon
Inline.

uncaged wrote:
Show quote
> I'm confused about using SuppressFinalize in Dispose.
>
> My class has a Socket member, so FxCop complained that my class needs to
> implement IDispose.
>
> Documentation says that either Dispose or the finalizer (destructor?) get
> called, but never both.  Is that because the examples have SuppressFinalize
> being called in Dispose?
>
> In my attempt to follow the examples, I've got a destructor that calls
> Dispose(false), a Dispose() that calls Dispose(true) and
> GC.SupressFinalize(this), and a Dispose(bool) that looks like:
>
> protected virtual void Dispose( Boolean disposing)
> {
>     if (! disposed)
>     {
>         if (disposing)
>         {
>             if (listenerSocket != null)
>             {
>                 listenerSocket.Close();
>                 listenerSocket = null;
>             }
>         }
>         disposed = true;
>     }
> }
>
> First of all, is this right?
>

Yes.  It looks fine to me.  You probably don't need to set
listenerSocket = null in this particular case, but it's not a big deal.

> Next, I'm confused about SuppressFinalize being called in Dispose().  My
> class has other object members.  Does my Dispose(bool) need to set them all
> to null in order for them to get cleaned up by garbage collection?

Well, techically yes.  But I think you're thinking about this the wrong
way.  In most use cases an object is no longer referenced after its
Dispose method has been called.  If it's no longer referenced then it,
along with its associated object graph, are all eligible for
collection.  That's why setting listenerSocket = null is usually not
needed.

>If not,  when are they available for collection?
>

They are available for collection whenever the GC cannot find a
reference to them.  Now, if you continue to hold a reference to your
class after calling Dispose then the other objects referenced inside
your class will not be eligible for collection either.  However, the
Socket will be eligible since you explicitly set its reference to null
inside the Dispose(bool) method.

> I'm also confused about the examples.  In the SuppressFinalize documentation
> (ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/M_System_GC_SuppressFinalize_1_b4c5a2da.htm),
> for example, in the Dispose(bool disposing) function, it says to dispose of
> managed resources only if disposing is true, but to dispose of unmanaged
> resource regardless of the value of disposing.  Socket is managed, but isn't
> it IDisposable because it manipulates an unmanaged resource?

Yes.  It is a managed object that holds unmanaged resources.  Since it
is a managed object only call it's Dispose (Close) method when
disposing is true.  It doesn't appear that your class holds unmanaged
resources *directly* so there's nothing else you need to do.

> So should I
> call Socket's Close only if disposing is true, or regardless?

Call Socket.Close or Socket.Dispose only if disposing is true.  If
disposing is false then the GC called the Dispose(bool) method and that
means managed object references may not be valid.  In other words, the
GC may have already called the Socket's Finalize method because the
order in which the GC calls Finalize is unpredictable.

> By the way,
> I'm supposed to call Close, right?  I thought I was supposed to call Socket's
> Dispose, but that's protected.
>

Calling Close is usually fine.  The Dispose method is public.  You're
just not seeing it because it's implemented explicitly.  You call it by
casting it into an IDisposable reference. 

Show quote
> Thanks.
Author
18 Mar 2006 4:03 AM
uncaged
Thanks, that was very helpful.

Show quote
"Brian Gideon" wrote:

> Inline.
>
> uncaged wrote:
> > I'm confused about using SuppressFinalize in Dispose.
> >
> > My class has a Socket member, so FxCop complained that my class needs to
> > implement IDispose.
> >
> > Documentation says that either Dispose or the finalizer (destructor?) get
> > called, but never both.  Is that because the examples have SuppressFinalize
> > being called in Dispose?
> >
> > In my attempt to follow the examples, I've got a destructor that calls
> > Dispose(false), a Dispose() that calls Dispose(true) and
> > GC.SupressFinalize(this), and a Dispose(bool) that looks like:
> >
> > protected virtual void Dispose( Boolean disposing)
> > {
> >     if (! disposed)
> >     {
> >         if (disposing)
> >         {
> >             if (listenerSocket != null)
> >             {
> >                 listenerSocket.Close();
> >                 listenerSocket = null;
> >             }
> >         }
> >         disposed = true;
> >     }
> > }
> >
> > First of all, is this right?
> >
>
> Yes.  It looks fine to me.  You probably don't need to set
> listenerSocket = null in this particular case, but it's not a big deal.
>
> > Next, I'm confused about SuppressFinalize being called in Dispose().  My
> > class has other object members.  Does my Dispose(bool) need to set them all
> > to null in order for them to get cleaned up by garbage collection?
>
> Well, techically yes.  But I think you're thinking about this the wrong
> way.  In most use cases an object is no longer referenced after its
> Dispose method has been called.  If it's no longer referenced then it,
> along with its associated object graph, are all eligible for
> collection.  That's why setting listenerSocket = null is usually not
> needed.
>
> >If not,  when are they available for collection?
> >
>
> They are available for collection whenever the GC cannot find a
> reference to them.  Now, if you continue to hold a reference to your
> class after calling Dispose then the other objects referenced inside
> your class will not be eligible for collection either.  However, the
> Socket will be eligible since you explicitly set its reference to null
> inside the Dispose(bool) method.
>
> > I'm also confused about the examples.  In the SuppressFinalize documentation
> > (ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/M_System_GC_SuppressFinalize_1_b4c5a2da.htm),
> > for example, in the Dispose(bool disposing) function, it says to dispose of
> > managed resources only if disposing is true, but to dispose of unmanaged
> > resource regardless of the value of disposing.  Socket is managed, but isn't
> > it IDisposable because it manipulates an unmanaged resource?
>
> Yes.  It is a managed object that holds unmanaged resources.  Since it
> is a managed object only call it's Dispose (Close) method when
> disposing is true.  It doesn't appear that your class holds unmanaged
> resources *directly* so there's nothing else you need to do.
>
> > So should I
> > call Socket's Close only if disposing is true, or regardless?
>
> Call Socket.Close or Socket.Dispose only if disposing is true.  If
> disposing is false then the GC called the Dispose(bool) method and that
> means managed object references may not be valid.  In other words, the
> GC may have already called the Socket's Finalize method because the
> order in which the GC calls Finalize is unpredictable.
>
> > By the way,
> > I'm supposed to call Close, right?  I thought I was supposed to call Socket's
> > Dispose, but that's protected.
> >
>
> Calling Close is usually fine.  The Dispose method is public.  You're
> just not seeing it because it's implemented explicitly.  You call it by
> casting it into an IDisposable reference. 
>
> > Thanks.
>
>
Author
18 Mar 2006 8:49 AM
Nick Hounsome
To clarify one point:

1. You need to implement IDisposable because the only thing that will call
Dispose() on your socket is your class. If you dont implement it or nobody
calls it then the socket will not be closed until the GC runs its finalizer
which is usually later than you would want.

2. You don't need to implement a finalizer because the GC will call the
finalizer of the socket when it collects it.
In fact even if you had a finalizer it should not touch the socket because
the GC can collect and finalize the socket BEFORE finalizing the object that
references it.

3. You suppress finalization after disposing as an optimization  because
there is an associated overhead (it keeps the object around longer than
necessary)

Show quote
"uncaged" <unca***@discussions.microsoft.com> wrote in message
news:9248E879-BBE5-46A2-AA75-CADCD7616620@microsoft.com...
> I'm confused about using SuppressFinalize in Dispose.
>
> My class has a Socket member, so FxCop complained that my class needs to
> implement IDispose.
>
> Documentation says that either Dispose or the finalizer (destructor?) get
> called, but never both.  Is that because the examples have
> SuppressFinalize
> being called in Dispose?
>
> In my attempt to follow the examples, I've got a destructor that calls
> Dispose(false), a Dispose() that calls Dispose(true) and
> GC.SupressFinalize(this), and a Dispose(bool) that looks like:
>
> protected virtual void Dispose( Boolean disposing)
> {
>    if (! disposed)
>    {
>        if (disposing)
>        {
>            if (listenerSocket != null)
>            {
>                listenerSocket.Close();
>                listenerSocket = null;
>            }
>        }
>        disposed = true;
>    }
> }
>
> First of all, is this right?
>
> Next, I'm confused about SuppressFinalize being called in Dispose().  My
> class has other object members.  Does my Dispose(bool) need to set them
> all
> to null in order for them to get cleaned up by garbage collection?  If
> not,
> when are they available for collection?
>
> I'm also confused about the examples.  In the SuppressFinalize
> documentation
> (ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/M_System_GC_SuppressFinalize_1_b4c5a2da.htm),
> for example, in the Dispose(bool disposing) function, it says to dispose
> of
> managed resources only if disposing is true, but to dispose of unmanaged
> resource regardless of the value of disposing.  Socket is managed, but
> isn't
> it IDisposable because it manipulates an unmanaged resource?  So should I
> call Socket's Close only if disposing is true, or regardless?  By the way,
> I'm supposed to call Close, right?  I thought I was supposed to call
> Socket's
> Dispose, but that's protected.
>
> Thanks.
>
Author
18 Mar 2006 6:24 PM
Jon Skeet [C# MVP]
Nick Hounsome <nh***@nickhounsome.me.uk> wrote:

<snip - I agree with most of the post>

> 2. You don't need to implement a finalizer because the GC will call the
> finalizer of the socket when it collects it.
> In fact even if you had a finalizer it should not touch the socket because
> the GC can collect and finalize the socket BEFORE finalizing the object that
> references it.

Not quite - it can finalize the socket, but it can't collect it. If the
referring object resurrects itself (eg assigning a reference to "this"
to a static field somewhere) then the socket object would have to be
kept alive too. It may well have been finalized before this, however,
in which case I wouldn't expect it to behave terribly nicely...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

AddThis Social Bookmark Button