When is it acceptable to call GC.Collect?

前端 未结 24 2148
挽巷
挽巷 2020-11-22 08:54

The general advise is that you should not call GC.Collect from your code, but what are the exceptions to this rule?

I can only think of a few very speci

相关标签:
24条回答
  • 2020-11-22 09:11

    You can call GC.Collect() when you know something about the nature of the app the garbage collector doesn't. It's tempting to think that, as the author, this is very likely. However, the truth is the GC amounts to a pretty well-written and tested expert system, and it's rare you'll know something about the low level code paths it doesn't.

    The best example I can think of where you might have some extra information is a app that cycles between idle periods and very busy periods. You want the best performance possible for the busy periods and therefore want to use the idle time to do some clean up.

    However, most of the time the GC is smart enough to do this anyway.

    0 讨论(0)
  • 2020-11-22 09:13

    Scott Holden's blog entry on when to (and when not to) call GC.Collect is specific to the .NET Compact Framework, but the rules generally apply to all managed development.

    0 讨论(0)
  • 2020-11-22 09:15

    If you have good reason to believe that a significant set of objects - particularly those you suspect to be in generations 1 and 2 - are now eligible for garbage collection, and that now would be an appropriate time to collect in terms of the small performance hit.

    A good example of this is if you've just closed a large form. You know that all the UI controls can now be garbage collected, and a very short pause as the form is closed probably won't be noticeable to the user.

    UPDATE 2.7.2018

    As of .NET 4.5 - there is GCLatencyMode.LowLatency and GCLatencyMode.SustainedLowLatency. When entering and leaving either of these modes, it is recommended that you force a full GC with GC.Collect(2, GCCollectionMode.Forced).

    As of .NET 4.6 - there is the GC.TryStartNoGCRegion method (used to set the read-only value GCLatencyMode.NoGCRegion). This can itself, perform a full blocking garbage collection in an attempt to free enough memory, but given we are disallowing GC for a period, I would argue it is also a good idea to perform full GC before and after.

    Source: Microsoft engineer Ben Watson's: Writing High-Performance .NET Code, 2nd Ed. 2018.

    See:

    • https://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode(v=vs.110).aspx
    • https://msdn.microsoft.com/en-us/library/dn906204(v=vs.110).aspx
    0 讨论(0)
  • 2020-11-22 09:15

    One useful place to call GC.Collect() is in a unit test when you want to verify that you are not creating a memory leak (e. g. if you are doing something with WeakReferences or ConditionalWeakTable, dynamically generated code, etc).

    For example, I have a few tests like:

    WeakReference w = CodeThatShouldNotMemoryLeak();
    Assert.IsTrue(w.IsAlive);
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Assert.IsFalse(w.IsAlive);
    

    It could be argued that using WeakReferences is a problem in and of itself, but it seems that if you are creating a system that relies on such behavior then calling GC.Collect() is a good way to verify such code.

    0 讨论(0)
  • 2020-11-22 09:15
    using(var stream = new MemoryStream())
    {
       bitmap.Save(stream, ImageFormat.Png);
       techObject.Last().Image = Image.FromStream(stream);
       bitmap.Dispose();
    
       // Without this code, I had an OutOfMemory exception.
       GC.Collect();
       GC.WaitForPendingFinalizers();
       //
    }
    
    0 讨论(0)
  • 2020-11-22 09:17

    One instance where it is almost necessary to call GC.Collect() is when automating Microsoft Office through Interop. COM objects for Office don't like to automatically release and can result in the instances of the Office product taking up very large amounts of memory. I'm not sure if this is an issue or by design. There's lots of posts about this topic around the internet so I won't go into too much detail.

    When programming using Interop, every single COM object should be manually released, usually though the use of Marshal.ReleseComObject(). In addition, calling Garbage Collection manually can help "clean up" a bit. Calling the following code when you're done with Interop objects seems to help quite a bit:

    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    

    In my personal experience, using a combination of ReleaseComObject and manually calling garbage collection greatly reduces the memory usage of Office products, specifically Excel.

    0 讨论(0)
提交回复
热议问题