0

I understand the basics of using the Dispose/Finalize pattern and I do use it wherever I can but I seem to have a problem with this situation.

I have a very small object:

// Small Object
public class Class1
{
    public int SampleId { get; set; }
}

// Form Level Object
public IList<Class1> MyClasses { get; set; }

MyClasses is populated by loading up to a few thousand of the Class1 objects from the DB. That process works properly.

Because there is no Dispose method on the List<> object and it is using a fair amount of memory I'm unsure of what to do with it. When the user closes the form do I allow the default Close() method to clean up MyClasses, should I use the MyClasses.Clear() to reduce the size of the list in the Dispose method, set MyClasses to null, or possibly something else?

Once the user closes this form they may open the form back up and load another set of data to work with that could be a few thousand in size. Over a few minutes they could be consuming a rather large amount of memory.

I would like to reclaim the memory MyClasses is using fairly quickly so I can reuse it for the next time the user opens the form.

What if Class1 had numerous fields in it making each record considerably larger, would it make a difference as to what methodology I should use to clean up MyClasses?

Chad
  • 23
  • 2
  • 1
    These are managed objects, when they go out of scope they garbage collector will collect them (when it feels the need). There is nothing more you need to worry about in most usual cases. .Net does not aggressively give back memory to the operating system, it does this by design. – TheGeneral Aug 04 '19 at 23:53
  • 2
    The garbage collector does not need your help. If you think you know better then just put your foot down and call GC.Collect(). Not noticing a difference *is* the expected outcome. – Hans Passant Aug 05 '19 at 00:02
  • 1
    `rather large amount of memory.` **How large** is a rather large amount of memory? – mjwills Aug 05 '19 at 00:18
  • @Hans, I definitely am trying to stay away from manually calling the GC. I've got 3 other developers that are trying to pepper the code with GC in order to fix the problem and I feel like I need to delete the calls. One dev added 3 GC's in a row in order to reclaim as much as possible, or at least that is what he told me he was attempting to do. – Chad Aug 05 '19 at 00:52
  • @mjwills, the example is a very simplified version of the problem but after loading the page just once we are looking at using about 250 MB for the app. After about an hour we had one user consuming over 5 GB of memory. We are not using any unmanaged resources other than an Excel Interop that does not get called in this process. – Chad Aug 05 '19 at 00:57
  • 1
    250MB is reasonable, and nothing to worry about. 5GB - well yes, you likely need to worry about that. You'll need to share a [mcve] that reproduces the issue. There is a 99% chance you have a large object (or objects) with a larger scope than it should have. – mjwills Aug 05 '19 at 01:05
  • Are you running Release or Debug build? – mjwills Aug 05 '19 at 01:05
  • 1
    `I've got 3 other developers that are trying to pepper the code with GC in order to fix the problem and I feel like I need to delete the calls.` Adding `GC.Collect` (or removing it) is very unlikely to help if your memory usage is slowly drifting up to GB (adding them _could_ help if it spikes then drops down). Being more specific is very hard, alas, without seeing real code. – mjwills Aug 05 '19 at 01:07
  • 1
    The problem here is probably the large object heap caused by the fact you are pulling thousands of rows back from the DB. – TheGeneral Aug 05 '19 at 01:14
  • Use a memory profiler to understand where you leak memory. If the memory keep increasing with time, then you probably have a leak somehow. – Phil1970 Aug 05 '19 at 01:37
  • `public IList MyClasses { get; set; }` Why public? This makes it possible for another part of the programs to keep a reference to the list, after the closing of the form. – Theodor Zoulias Aug 05 '19 at 03:33

1 Answers1

0

Short answer: You don't need to worry about trying to reclaim the memory of a List.

Longer answer: You can read about .NET's garbage collection here. Whenever managed objects (object of a .NET type) are not referenced by any variable anymore, they become subject to the garbage collector. They'll get cleaned up automagically.

If you're having problems with your app taking too much memory, you're either:

  1. Retrieving more data than you actually need (look for places where you might be retrieving large data sets and filtering in-memory, rather than applying the filtering during retrieval)
  2. You're keeping a reference to old data that you don't need anymore, which prevents the GC from touching it.
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Don't worry because it is not a managed object with a Dispose(), correct? With the first pass of the garbage collector does it just reclaim the list or would it be able to reclaim the list and all of the Class1 objects as well? – Chad Aug 05 '19 at 00:50
  • Once the memory for the list itself is reclaimed, the `Class1` instances are now unreferenced and are subject to garbage collection. I don't know if that will happen on the same run of the GC or on the next. – Gabriel Luci Aug 05 '19 at 02:49
  • The only time I've ever had problems with memory was on a long-running loop that was creating objects on each iteration of the loop. Because the loop was processor-intensive, the GC didn't have time to run. But it was also creating `IDisposable` objects (`DirectoryEntry`, to be specific), so all I had to do to fix it was call `.Dispose()` on those objects. – Gabriel Luci Aug 05 '19 at 02:55
  • We did have a reference from another location. We were passing the collection to a common static method in a helper class. The method was holding on to a reference to the collection if it found certain characteristics. Over time it was holding on to several million records causing the memory leak. And the helper class had the DebuggerStepThrough attribute so when I believed I was stepping into each method it actually prevented me. – Chad Aug 05 '19 at 04:24