Home All Groups Group Topic Archive Search About
Author
20 Jun 2006 4:52 PM
Petros Amiridis
Hi,

When I create an instance of one of my classes inside a method, does it
make a difference if I call its Dispose method?

public class Foo : IDisposable
{
  public Foo
  {
  }

  public Foo anotherFoo = null;

  public void Dispose()
  {
  }
}

Given the class above is there a difference between the two examples
below? When will the GC give back the memory? Does ExampleA confuse GC
when it comes to tracking and releasing foo2?

public void ExampleA()
{
  Foo foo1 = new Foo();
  Foo foo2 = new Foo();
  Foo foo3 = new Foo();
  foo1.anotherFoo = foo2;
  foo1.anotherFoo = foo3;
}

public void ExampleB()
{
  Foo foo1 = new Foo();
  Foo foo2 = new Foo();
  Foo foo3 = new Foo();
  foo1.anotherFoo = foo2;
  foo2.Dispose();
  foo1.anotherFoo = foo3;
  foo1.Dispose();
  foo3.Dispose();
}

Thanx,

--
Petros

Author
20 Jun 2006 8:23 PM
Phil Wilson
You example doesn't help because there's nothing in Foo that needs
disposing, and Dispose isn't related to GC as you seem to be assuming.
--
Phil Wilson [MVP Windows Installer]
----
Show quote
"Petros Amiridis" <pet***@nowhere.net> wrote in message
news:%23shS3nIlGHA.1320@TK2MSFTNGP04.phx.gbl...
> Hi,
>
> When I create an instance of one of my classes inside a method, does it
> make a difference if I call its Dispose method?
>
> public class Foo : IDisposable
> {
>  public Foo
>  {
>  }
>
>  public Foo anotherFoo = null;
>
>  public void Dispose()
>  {
>  }
> }
>
> Given the class above is there a difference between the two examples
> below? When will the GC give back the memory? Does ExampleA confuse GC
> when it comes to tracking and releasing foo2?
>
> public void ExampleA()
> {
>  Foo foo1 = new Foo();
>  Foo foo2 = new Foo();
>  Foo foo3 = new Foo();
>  foo1.anotherFoo = foo2;
>  foo1.anotherFoo = foo3;
> }
>
> public void ExampleB()
> {
>  Foo foo1 = new Foo();
>  Foo foo2 = new Foo();
>  Foo foo3 = new Foo();
>  foo1.anotherFoo = foo2;
>  foo2.Dispose();
>  foo1.anotherFoo = foo3;
>  foo1.Dispose();
>  foo3.Dispose();
> }
>
> Thanx,
>
> --
> Petros
Author
21 Jun 2006 4:33 AM
Petros Amiridis
Phil Wilson wrote:

> You example doesn't help because there's nothing in Foo that needs
> disposing, and Dispose isn't related to GC as you seem to be assuming.

What if it does have something that needs disposing? An if Dispose
doesn't have anything to do with GC, could tell me briefly what are
good practices that can make your application consume less memory?

I've noticed that my application starts and consumes several times more
memory than equivalent native applications. The problem is that
whenever I open/close windows in my application, the memory that it
occupies grows more. I wait and nothing happens. Shouldn't GC release
the memory as long as an object is not referenced any more?

Thank you,

--
Petros
Author
21 Jun 2006 12:46 PM
Daniel Billingsley
Show quote
"Petros Amiridis" <pet***@nowhere.net> wrote in message
news:OyV$mvOlGHA.1204@TK2MSFTNGP02.phx.gbl...
> Phil Wilson wrote:
>
>> You example doesn't help because there's nothing in Foo that needs
>> disposing, and Dispose isn't related to GC as you seem to be assuming.
>
> What if it does have something that needs disposing? An if Dispose
> doesn't have anything to do with GC, could tell me briefly what are
> good practices that can make your application consume less memory?
>
> I've noticed that my application starts and consumes several times more
> memory than equivalent native applications. The problem is that
> whenever I open/close windows in my application, the memory that it
> occupies grows more. I wait and nothing happens. Shouldn't GC release
> the memory as long as an object is not referenced any more?
>

I think to some degree it's a waste of time trying to help GC do its job
better in the way it seems you're thinking, as it is a fairly indeterminate
mechanism in the first place.  It is somewhat important in some cases to
help GC have less to do though, because it can become a performance issue.
For example, using lots of stringbuilders for what are really just simple
concatenations.  But that really manifests itself as a performance issue
more than a memory one in my testing.

As somebody else said, the Dispose pattern is for making sure UNMANAGED
resources inside your classes get cleaned up.  That is, making sure there
are no memory leaks in things that GC doesn't try to deal with.  That's why
the statement "Dispose doesn't have anything to do with GC".

I have no idea what "several times more memory than equivalent native
applications" means.  Equivalent how -Functionality?  Code?  That's such a
nebulous comparison I don't think I'd spend much time worrying about that
either.

Is there a specific problem you're having or specific reason you think you
may have a memory leak in the application?
Author
21 Jun 2006 1:22 PM
Petros Amiridis
Daniel Billingsley wrote:

> As somebody else said, the Dispose pattern is for making sure
> UNMANAGED resources inside your classes get cleaned up.

This more clear to me now. I really thought Dispose would help GC.
Thank you and the rest for the clarification.

> I have no idea what "several times more memory than equivalent native
> applications" means.  Equivalent how -Functionality?  Code?  That's
> such a nebulous comparison I don't think I'd spend much time worrying
> about that either.

I admit that is based entirely on my experience and not in crystal
clear measurements. My heuristics mechanism takes under consideration
all the factors: Functionality, Number of Forms etc. Sure, I might be
inaccurate in my comparison, but the numbers are very different between
native and managed applications. My native applications take memory and
give it back as soon as I don't need the resources I've used. In
managed applications, the memory keeps being eaten until the GC decides
it is time to collect. The problem with this is that my customer does
run more applications than one. The customer also uses his computer for
other puproses, so she runs third party applications too. So to
conclude, I don't have a specific problem, other than the need to tell
my customers to add some more memory to their machines. Maybe it is not
a leak, it is just taking the GC a long time to collect back the memory.

--
Petros
Author
21 Jun 2006 3:36 PM
Simon Hart
Show quote
"Petros Amiridis" <pet***@nowhere.net> wrote in message
news:ewLX8WTlGHA.3396@TK2MSFTNGP05.phx.gbl...
> Daniel Billingsley wrote:
>
>> As somebody else said, the Dispose pattern is for making sure
>> UNMANAGED resources inside your classes get cleaned up.
>
> This more clear to me now. I really thought Dispose would help GC.
> Thank you and the rest for the clarification.
>
>> I have no idea what "several times more memory than equivalent native
>> applications" means.  Equivalent how -Functionality?  Code?  That's
>> such a nebulous comparison I don't think I'd spend much time worrying
>> about that either.
>
> I admit that is based entirely on my experience and not in crystal
> clear measurements. My heuristics mechanism takes under consideration
> all the factors: Functionality, Number of Forms etc. Sure, I might be
> inaccurate in my comparison, but the numbers are very different between
> native and managed applications. My native applications take memory and
> give it back as soon as I don't need the resources I've used. In
> managed applications, the memory keeps being eaten until the GC decides
> it is time to collect. The problem with this is that my customer does
> run more applications than one. The customer also uses his computer for
> other puproses, so she runs third party applications too. So to
> conclude, I don't have a specific problem, other than the need to tell
> my customers to add some more memory to their machines. Maybe it is not
> a leak, it is just taking the GC a long time to collect back the memory.

The GC will kick in when required - for example memory is low, but it will
only release managed
objects if: A. They have been marked to be Diposed or B. They are
unreachable on the heap.

Regards
Simon.
Author
21 Jun 2006 10:19 PM
Göran_Andersson
Simon Hart wrote:
Show quote
> "Petros Amiridis" <pet***@nowhere.net> wrote in message
> news:ewLX8WTlGHA.3396@TK2MSFTNGP05.phx.gbl...
>> Daniel Billingsley wrote:
>>
>>> As somebody else said, the Dispose pattern is for making sure
>>> UNMANAGED resources inside your classes get cleaned up.
>> This more clear to me now. I really thought Dispose would help GC.
>> Thank you and the rest for the clarification.
>>
>>> I have no idea what "several times more memory than equivalent native
>>> applications" means.  Equivalent how -Functionality?  Code?  That's
>>> such a nebulous comparison I don't think I'd spend much time worrying
>>> about that either.
>> I admit that is based entirely on my experience and not in crystal
>> clear measurements. My heuristics mechanism takes under consideration
>> all the factors: Functionality, Number of Forms etc. Sure, I might be
>> inaccurate in my comparison, but the numbers are very different between
>> native and managed applications. My native applications take memory and
>> give it back as soon as I don't need the resources I've used. In
>> managed applications, the memory keeps being eaten until the GC decides
>> it is time to collect. The problem with this is that my customer does
>> run more applications than one. The customer also uses his computer for
>> other puproses, so she runs third party applications too. So to
>> conclude, I don't have a specific problem, other than the need to tell
>> my customers to add some more memory to their machines. Maybe it is not
>> a leak, it is just taking the GC a long time to collect back the memory.
>
> The GC will kick in when required - for example memory is low, but it will
> only release managed
> objects if: A. They have been marked to be Diposed or B. They are
> unreachable on the heap.
>
> Regards
> Simon.

Actually only condition B is relevant.

You can't mark objects to be collected, the only way to make them
collectable is to make them unreachable.
Author
21 Jun 2006 1:49 PM
Carl Daniel [VC++ MVP]
Daniel Billingsley wrote:
> As somebody else said, the Dispose pattern is for making sure
> UNMANAGED resources inside your classes get cleaned up.

I would take exception with that statement.  Dispose is for making sure
resources that are not simply managed heap allocations get cleaned up.
Unmanaged resources such as handles or Win32 memory allocations are fine
examples of such, but there are certainly managed examples as well.  A
common example of a managed resource that needs to be explicitly cleaned up
is a callback (delegate) which can keep an object alive long after you're
done with it, consuming both memory and CPU resources making callbacks to an
object that no one cares about anymore.

-cd
Author
21 Jun 2006 3:34 PM
Simon Hart
Agree. We often use the Dispose (IDisposable) for cleaning managed resources
as well as unmanaged. We tend to use the Finalizer (Destructor) for
unmanaged deallocation.

Regards
Simon.

Show quote
"Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
wrote in message news:uuTrPmTlGHA.4536@TK2MSFTNGP04.phx.gbl...
> Daniel Billingsley wrote:
>> As somebody else said, the Dispose pattern is for making sure
>> UNMANAGED resources inside your classes get cleaned up.
>
> I would take exception with that statement.  Dispose is for making sure
> resources that are not simply managed heap allocations get cleaned up.
> Unmanaged resources such as handles or Win32 memory allocations are fine
> examples of such, but there are certainly managed examples as well.  A
> common example of a managed resource that needs to be explicitly cleaned
> up is a callback (delegate) which can keep an object alive long after
> you're done with it, consuming both memory and CPU resources making
> callbacks to an object that no one cares about anymore.
>
> -cd
>
>
Author
21 Jun 2006 6:48 PM
Markus Stoeger
Simon Hart wrote:
> Agree. We often use the Dispose (IDisposable) for cleaning managed resources
> as well as unmanaged. We tend to use the Finalizer (Destructor) for
> unmanaged deallocation.

Could you explain why you prefer the finalizer instead of a manual call
to Dispose for freeing unmanaged resources?

As far as I know you can never tell when the GC will finalize an object.
So it might keep floating around forever as well. Which means that you
could run out of handles for example.

Maybe I've misunderstood something behind GC and the finalizer?.

Max
Author
21 Jun 2006 10:23 PM
Göran_Andersson
Markus Stoeger wrote:
Show quote
> Simon Hart wrote:
>> Agree. We often use the Dispose (IDisposable) for cleaning managed
>> resources as well as unmanaged. We tend to use the Finalizer
>> (Destructor) for unmanaged deallocation.
>
> Could you explain why you prefer the finalizer instead of a manual call
> to Dispose for freeing unmanaged resources?
>
> As far as I know you can never tell when the GC will finalize an object.
> So it might keep floating around forever as well. Which means that you
> could run out of handles for example.
>
> Maybe I've misunderstood something behind GC and the finalizer?.
>
> Max

No, that is correct.

The Dispose method should be used to free resources. The finalizer
should call Dispose as a backup if the program failed to call it.
Author
21 Jun 2006 11:12 PM
Carl Daniel [VC++ MVP]
Show quote
"Göran Andersson" <gu***@guffa.com> wrote in message
news:evglUFYlGHA.2128@TK2MSFTNGP04.phx.gbl...
> Markus Stoeger wrote:
>> Simon Hart wrote:
>>> Agree. We often use the Dispose (IDisposable) for cleaning managed
>>> resources as well as unmanaged. We tend to use the Finalizer
>>> (Destructor) for unmanaged deallocation.
>>
>> Could you explain why you prefer the finalizer instead of a manual call
>> to Dispose for freeing unmanaged resources?
>>
>> As far as I know you can never tell when the GC will finalize an object.
>> So it might keep floating around forever as well. Which means that you
>> could run out of handles for example.
>>
>> Maybe I've misunderstood something behind GC and the finalizer?.
>>
>> Max
>
> No, that is correct.
>
> The Dispose method should be used to free resources. The finalizer should
> call Dispose as a backup if the program failed to call it.

More specifically, the recommended structure for Finalize and Dispose is:

class C : IDisposable
{
    void IDisposable.Dispose()
    {
        Dispose(true);
    }

    ~C()
    {
        Dispose(false)
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // free managed resources here

            GC.SuppressFinalize(this);
        }

        // free unmanaged resources here
    }
}

The C++/CLI compiler automatically implements this structure, while in C#/VB
you have to do it yourself.  Current versions of FxCop will raise warnings
if your class implements IDisposable but doesn't do it this way.

Of course, if your class cannot be derived from, then there's no need for
Dispose(bool) to be virtual.

-cd

-cd
Author
22 Jun 2006 11:51 AM
Michael D. Ober
I don't know about the C# environment, but VB 2005 can be configured to
insert the dispose pattern, as well as other implementation patterns, when
you add the Implements clause to the class definition and press return.

Mike Ober.

Show quote
"Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
wrote in message news:%23V$RCfYlGHA.1240@TK2MSFTNGP05.phx.gbl...
> "Göran Andersson" <gu***@guffa.com> wrote in message
> news:evglUFYlGHA.2128@TK2MSFTNGP04.phx.gbl...
> > Markus Stoeger wrote:
> >> Simon Hart wrote:
> >>> Agree. We often use the Dispose (IDisposable) for cleaning managed
> >>> resources as well as unmanaged. We tend to use the Finalizer
> >>> (Destructor) for unmanaged deallocation.
> >>
> >> Could you explain why you prefer the finalizer instead of a manual call
> >> to Dispose for freeing unmanaged resources?
> >>
> >> As far as I know you can never tell when the GC will finalize an
object.
> >> So it might keep floating around forever as well. Which means that you
> >> could run out of handles for example.
> >>
> >> Maybe I've misunderstood something behind GC and the finalizer?.
> >>
> >> Max
> >
> > No, that is correct.
> >
> > The Dispose method should be used to free resources. The finalizer
should
> > call Dispose as a backup if the program failed to call it.
>
> More specifically, the recommended structure for Finalize and Dispose is:
>
> class C : IDisposable
> {
>     void IDisposable.Dispose()
>     {
>         Dispose(true);
>     }
>
>     ~C()
>     {
>         Dispose(false)
>     }
>
>     protected virtual void Dispose(bool disposing)
>     {
>         if (disposing)
>         {
>             // free managed resources here
>
>             GC.SuppressFinalize(this);
>         }
>
>         // free unmanaged resources here
>     }
> }
>
> The C++/CLI compiler automatically implements this structure, while in
C#/VB
> you have to do it yourself.  Current versions of FxCop will raise warnings
> if your class implements IDisposable but doesn't do it this way.
>
> Of course, if your class cannot be derived from, then there's no need for
> Dispose(bool) to be virtual.
>
> -cd
>
> -cd
>
>
Author
22 Jun 2006 11:31 AM
Daniel Billingsley
Let's talk.  :)

This would apply to simple events then, since they are really just fancy
delegates.  I've never heard of anybody talk of implementing Dispose in a
class just because it raises events.  Should we?

Let's lay some groundwork.  The problem with keeping an object "alive" is
because something references it, not the other way around.  Let's imagine an
ObjectB that has a reference to ObjectA because ObjectA was previously
hooked to an event in ObjectB (creating a delegate reference as you
describe).

Now ObjectB goes out of scope.  It obviously isn't "making callbacks" any
more, so there's no reason for it to have Dispose() for that reason.  The
problem with keeping ObjectA "alive" consuming memory is only temporary
until GC does its thing with ObjectB.  That's the whole point of GC.

But, for you GC gurus - isn't GC smart enough to know that the only
reference to ObjectA is from a "dead" ObjectB and therefore consider ObjectA
itself eligible for collection?

Show quote
"Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
wrote in message news:uuTrPmTlGHA.4536@TK2MSFTNGP04.phx.gbl...
> Daniel Billingsley wrote:
>> As somebody else said, the Dispose pattern is for making sure
>> UNMANAGED resources inside your classes get cleaned up.
>
> I would take exception with that statement.  Dispose is for making sure
> resources that are not simply managed heap allocations get cleaned up.
> Unmanaged resources such as handles or Win32 memory allocations are fine
> examples of such, but there are certainly managed examples as well.  A
> common example of a managed resource that needs to be explicitly cleaned
> up is a callback (delegate) which can keep an object alive long after
> you're done with it, consuming both memory and CPU resources making
> callbacks to an object that no one cares about anymore.
>
> -cd
>
>
Author
22 Jun 2006 11:52 AM
Michael D. Ober
Show quote
"Daniel Billingsley" <DanielBillingsley@newsgroup.nospam> wrote in message
news:eJvcc9elGHA.4100@TK2MSFTNGP05.phx.gbl...
> Let's talk.  :)
>
> This would apply to simple events then, since they are really just fancy
> delegates.  I've never heard of anybody talk of implementing Dispose in a
> class just because it raises events.  Should we?
>
> Let's lay some groundwork.  The problem with keeping an object "alive" is
> because something references it, not the other way around.  Let's imagine
an
> ObjectB that has a reference to ObjectA because ObjectA was previously
> hooked to an event in ObjectB (creating a delegate reference as you
> describe).
>
> Now ObjectB goes out of scope.  It obviously isn't "making callbacks" any
> more, so there's no reason for it to have Dispose() for that reason.  The
> problem with keeping ObjectA "alive" consuming memory is only temporary
> until GC does its thing with ObjectB.  That's the whole point of GC.
>
> But, for you GC gurus - isn't GC smart enough to know that the only
> reference to ObjectA is from a "dead" ObjectB and therefore consider
ObjectA
> itself eligible for collection?

Yes it is.  I have explicitely tested this scenerio.

Mike.

Show quote
>
> "Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
> wrote in message news:uuTrPmTlGHA.4536@TK2MSFTNGP04.phx.gbl...
> > Daniel Billingsley wrote:
> >> As somebody else said, the Dispose pattern is for making sure
> >> UNMANAGED resources inside your classes get cleaned up.
> >
> > I would take exception with that statement.  Dispose is for making sure
> > resources that are not simply managed heap allocations get cleaned up.
> > Unmanaged resources such as handles or Win32 memory allocations are fine
> > examples of such, but there are certainly managed examples as well.  A
> > common example of a managed resource that needs to be explicitly cleaned
> > up is a callback (delegate) which can keep an object alive long after
> > you're done with it, consuming both memory and CPU resources making
> > callbacks to an object that no one cares about anymore.
> >
> > -cd
> >
> >
>
>
Author
22 Jun 2006 12:07 PM
Göran_Andersson
Yes, it is.

When the GC does it's thing, it starts out by considering all objects as
collectable, then looks for references to find out which objects are not
collectable. As it doesn't look in collectable objects for references,
it still sees that unreachable objects are collectable although they
reference each other.

"Every object charged with being collectable will be presumed guilty
until proved reachable." ;)

Daniel Billingsley wrote:
Show quote
> Let's talk.  :)
>
> This would apply to simple events then, since they are really just fancy
> delegates.  I've never heard of anybody talk of implementing Dispose in a
> class just because it raises events.  Should we?
>
> Let's lay some groundwork.  The problem with keeping an object "alive" is
> because something references it, not the other way around.  Let's imagine an
> ObjectB that has a reference to ObjectA because ObjectA was previously
> hooked to an event in ObjectB (creating a delegate reference as you
> describe).
>
> Now ObjectB goes out of scope.  It obviously isn't "making callbacks" any
> more, so there's no reason for it to have Dispose() for that reason.  The
> problem with keeping ObjectA "alive" consuming memory is only temporary
> until GC does its thing with ObjectB.  That's the whole point of GC.
>
> But, for you GC gurus - isn't GC smart enough to know that the only
> reference to ObjectA is from a "dead" ObjectB and therefore consider ObjectA
> itself eligible for collection?
>
> "Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
> wrote in message news:uuTrPmTlGHA.4536@TK2MSFTNGP04.phx.gbl...
>> Daniel Billingsley wrote:
>>> As somebody else said, the Dispose pattern is for making sure
>>> UNMANAGED resources inside your classes get cleaned up.
>> I would take exception with that statement.  Dispose is for making sure
>> resources that are not simply managed heap allocations get cleaned up.
>> Unmanaged resources such as handles or Win32 memory allocations are fine
>> examples of such, but there are certainly managed examples as well.  A
>> common example of a managed resource that needs to be explicitly cleaned
>> up is a callback (delegate) which can keep an object alive long after
>> you're done with it, consuming both memory and CPU resources making
>> callbacks to an object that no one cares about anymore.
>>
>> -cd
>>
Author
20 Jun 2006 8:23 PM
Markus Stoeger
Petros Amiridis wrote:
> Hi,
>
> When I create an instance of one of my classes inside a method, does it
> make a difference if I call its Dispose method?

Sure. If an object is IDisposable, you have to call Dispose on it sooner
or later (not necessarly in the same method). If you don't, you might
create a resource leak which will make your program randomly throw
OutOfMemoryExceptions at your users.

Calling Dispose has no effect on when the memory of your managed objects
will get freed by the GC though.

hth,
Max
Author
21 Jun 2006 4:37 AM
Petros Amiridis
Markus Stoeger wrote:
> [...]
> Calling Dispose has no effect on when the memory of your managed
> objects will get freed by the GC though.

What should I be careful of not doing in order to avoid resource leaks
apart from calling Dispose?

Thank you,

--
Petros

AddThis Social Bookmark Button