When is it acceptable to call GC.Collect?

前端 未结 24 2149
挽巷
挽巷 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:18

    one good reason for calling GC is on small ARM computers with little memory, like the Raspberry PI (running with mono). If unallocated memory fragments use too much of the system RAM, then the Linux OS can get unstable. I have an application where I have to call GC every second (!) to get rid of memory overflow problems.

    Another good solution is to dispose objects when they are no longer needed. Unfortunately this is not so easy in many cases.

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

    i am still pretty unsure about this. I am working since 7 years on an Application Server. Our bigger installations take use of 24 GB Ram. Its hightly Multithreaded, and ALL calls for GC.Collect() ran into really terrible performance issues.

    Many third party Components used GC.Collect() when they thought it was clever to do this right now. So a simple bunch of Excel-Reports blocked the App Server for all threads several times a minute.

    We had to refactor all the 3rd Party Components in order to remove the GC.Collect() calls, and all worked fine after doing this.

    But i am running Servers on Win32 as well, and here i started to take heavy use of GC.Collect() after getting a OutOfMemoryException.

    But i am also pretty unsure about this, because i often noticed, when i get a OOM on 32 Bit, and i retry to run the same Operation again, without calling GC.Collect(), it just worked fine.

    One thing i wonder is the OOM Exception itself... If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(), defrag memory (??), try again, and if i still cant find a free memory block, then i would throw the OOM-Exception.

    Or at least make this behavior as configurable option, due the drawbacks of the performance issue with GC.Collect.

    Now i have lots of code like this in my app to "solve" the problem:

    public static TResult ExecuteOOMAware<T1, T2, TResult>(Func<T1,T2 ,TResult> func, T1 a1, T2 a2)
    {
    
        int oomCounter = 0;
        int maxOOMRetries = 10;
        do
        {
            try
            {
                return func(a1, a2);
            }
            catch (OutOfMemoryException)
            {
                oomCounter++;
                if (maxOOMRetries > 10)
                {
                    throw;
                }
                else
                {
                    Log.Info("OutOfMemory-Exception caught, Trying to fix. Counter: " + oomCounter.ToString());
                    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(oomCounter * 10));
                    GC.Collect();
                }
            }
        } while (oomCounter < maxOOMRetries);
    
        // never gets hitted.
        return default(TResult);
    }
    

    (Note that the Thread.Sleep() behavior is a really App apecific behavior, because we are running a ORM Caching Service, and the service takes some time to release all the cached objects, if RAM exceeds some predefined values. so it waits a few seconds the first time, and has increased waiting time each occurence of OOM.)

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

    Since there are Small object heap(SOH) and Large object heap(LOH)

    We can call GC.Collect() to clear de-reference object in SOP, and move lived object to next generation.

    In .net4.5, we can also compact LOH by using largeobjectheapcompactionmode

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

    One case is when you are trying to unit test code that uses WeakReference.

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

    The best practise is to not force a garbage collection in most cases. (Every system I have worked on that had forced garbage collections, had underlining problems that if solved would have removed the need to forced the garbage collection, and speeded the system up greatly.)

    There are a few cases when you know more about memory usage then the garbage collector does. This is unlikely to be true in a multi user application, or a service that is responding to more then one request at a time.

    However in some batch type processing you do know more then the GC. E.g. consider an application that.

    • Is given a list of file names on the command line
    • Processes a single file then write the result out to a results file.
    • While processing the file, creates a lot of interlinked objects that can not be collected until the processing of the file have complete (e.g. a parse tree)
    • Does not keep match state between the files it has processed.

    You may be able to make a case (after careful) testing that you should force a full garbage collection after you have process each file.

    Another cases is a service that wakes up every few minutes to process some items, and does not keep any state while it’s asleep. Then forcing a full collection just before going to sleep may be worthwhile.

    The only time I would consider forcing a collection is when I know that a lot of object had been created recently and very few objects are currently referenced.

    I would rather have a garbage collection API when I could give it hints about this type of thing without having to force a GC my self.

    See also "Rico Mariani's Performance Tidbits"

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

    As a memory fragmentation solution. I was getting out of memory exceptions while writing a lot of data into a memory stream (reading from a network stream). The data was written in 8K chunks. After reaching 128M there was exception even though there was a lot of memory available (but it was fragmented). Calling GC.Collect() solved the issue. I was able to handle over 1G after the fix.

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