How soon after disposing is memory available?

110 Views Asked by At

Is it instantaneous after the GC runs?

I was monitoring Memory (Available MBytes) using perfmon while running an application I'm working on. As I loaded files I could see the Available MBytes going down as expected, but as I closed them it didn't go back up so I'm wondering if I am not disposing correctly or if there is something else that affects this.

When a file is loaded:

  • the contents are stored in some objects
  • a new instance of a UserControl is created
  • a new TabPage is created
  • the UserControl is added to the TabPage
  • the TabPage is added to the TabControl

Reading on SO I saw that one of the most common things that can cause Memory Leaks is not unsubscribing from event handlers and so I made sure I did that in my UserControl's dispose method. I subscribe to the 'RemovingTab' event of the TabControl but the TabPages themselves have no attached handlers.

When closing a file, I remove stored instances of the objects and call dispose on both the UserControl and the TabPage. I tried running the CLR profiler (which I haven't had any experience with) and it said there was no GC runs.

2

There are 2 best solutions below

0
On

Is it instantaneous after the GC runs?

No. As a matter of fact, depending on the memory pressure of your particular application, the GC might not free up any memory during the whole lifespan of your application.

Reading on SO I saw that one of the most common things that can cause Memory Leaks is not unsubscribing from event handlers and so I made sure I did that in my UserControl's dispose method.

Yes that is a common cause.

When closing a file, I remove stored instances of the objects and call dispose on both the UserControl and the TabPage. I tried running the CLR profiler (which I haven't had any experience with) and it said there was no GC runs.

The GC is very good at doing what it's supposed to do and it has been fined tuned to extremes. If it doesn't run its probably because it has decided that it doesn't need to run. Therefore, when the memory is freed up by the GC is up to the GC to decide and, if I'm not mistaken, is implementation defined, so it is not something you can rely upon.

And last but not least, the IDisposable pattern is not, by any means, a deterministic pattern for reclaiming memory; that is most definitely not the pattern's goal.

0
On

Another common source of memory not being released is holding onto unmanaged resources, open files being one example.

The memory is available after the GC cleans up whatever is using it. Not every GC run results in memory being released. Any object that survives at least one GC run can end up living a long time because it's no longer in generation 0 - those could end up being around until the app actually needs more memory than is currently available to it. Large objects (larger than 85kb, as far as I remember) are stored on the large object heap which also isn't part of every GC run.

Your best bet is to look at what is actually holding the memory. Use the Visual Studio performance tools or try PerfView. Once you know what is actually holding the memory you'll be in a better position to figure out how to get it released.