Graviton
Graviton

Reputation: 83296

Can Dispose really free the memory if there are other objects pointing to it?

I have such a code:

    public class A: IDisposable
    {
       public CPlusCode cPlusCode{get;set;}

    public void CallB()
    {
       using(bCode = new B(cPlusCode))
       {
              //do everything in B
       }
    }

   public void Dispose()
   {
         cPlusCode.Dispose();
    }
    }

    public class B: IDisposable
    {
    private CPlusCode cpp;
      public B(CPlusCode cPlus)
    {
    cpp= cPlus;
    }
    public void Dispose()
   {
   cpp.Dispose();
  //dispose everything
    }
    }

   public static void Main()
   {
             for(int i=0; i<100000; i++)
                {
                      var aObject = new A();
                     aObject .CallB();
                }
    }

The issue is that when I execute Main, and B eats up a lot of memory to instantiate, and from my observation it seems that the memory eaten by the program is not freed up.

Can Dispose really free the memory if there are other objects pointing to it?

Upvotes: 1

Views: 238

Answers (5)

Daniel Earwicker
Daniel Earwicker

Reputation: 116744

Dispose is just a method. It doesn't have to do anything at all.

After calling Dispose on an object, the object still exists, but can no longer be safely used. The runtime doesn't assist in enforcing this, however. A "solid" implementation of Dispose (one designed to assist in catching bugs) would set a _disposed flag inside the object to true, and every other method on the object would throw ObjectDisposedException if that flag is true (the Dispose method itself should silently ignore further calls). But it is totally up to the implementer how far they go in enforcing this pattern.

An example would be FileStream. When it has an open file, the process's handle count will have increased by 1. When you call Dispose on it, the handle count will decrease. But this is only because the author of FileStream wrote their Dispose method to make that happen.

Which leads to the next problem - you can see the process's handle count in Task Manager and that is a very simple counter, but how are you measuring the memory usage? Note that the numbers shown in Task Manager are far from straightforward measures.

Upvotes: 2

vgru
vgru

Reputation: 51292

If you have implemented it correctly, and you are releasing all unmanaged resources inside Dispose(), then the object should be collected (or better, will be eligible for collection) after you release all references to that object.

Note, however, that you are not disposing object A in your example, which is also IDisposable. If A contains a reference to B, and you don't dispose A, then this might delay the collection of B as well (in case that A has some unmanaged stuff which may be creating a reference to A).

Since unmanaged code seems to be referenced by A in your example, A should be responsible for disposing it.

Upvotes: 0

Guffa
Guffa

Reputation: 700770

from my observation it seems that the memory eaten by the program is not freed up.

That is perfectly normal. The program will hang on to a certain amount of unused memory, and this will be released if the system really needs it.

One might think that the best thing for performance would be to keep the memory usage as small as possible, but it's actually the other way around. The computer doesn't benefit anything at all from having a lot of unused memory, so for best performance the application should not do the extra work to minimise the memory usage until it's really needed.

Can Dispose really free the memory if there are other objects pointing to it?

Yes and no...

Calling Dispose on an object will not free the object itself, however if the object contains other objects, those can be released by the Dispose method. That will not free any memory by itself, but it will let the garbage collector do it on the next run.

Upvotes: 0

Brian Rasmussen
Brian Rasmussen

Reputation: 116481

IDisposable has nothing to do with reclaiming managed memory. IDisposable allows types to free resources not handled by garbage collection such as handles etc. For normal .NET types, the garbage collector will handle reclaiming memory when the objects are no longer referenced.

Upvotes: 6

Mitch Wheat
Mitch Wheat

Reputation: 300769

The GC will run when it decides it needs to, so 'timely' is not relevant. It will happen when it happens; i.e. it is non-deterministic

Upvotes: 2

Related Questions