When is it acceptable to call GC.Collect?

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

    There are some situations where it is better safe than sorry.

    Here is one situation.

    It is possible to author an unmanaged DLL in C# using IL rewrites (because there are situations where this is necessary).

    Now suppose, for example, the DLL creates an array of bytes at the class level - because many of the exported functions need access to such. What happens when the DLL is unloaded? Is the garbage collector automatically called at that point? I don't know, but being an unmanaged DLL it is entirely possible the GC isn't called. And it would be a big problem if it wasn't called. When the DLL is unloaded so too would be the garbage collector - so who is going to be responsible for collecting any possible garbage and how would they do it? Better to employ C#'s garbage collector. Have a cleanup function (available to the DLL client) where the class level variables are set to null and the garbage collector called.

    Better safe than sorry.

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

    The short answer is: never!

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

    I was doing some performance testing on array and list:

    private static int count = 100000000;
    private static List<int> GetSomeNumbers_List_int()
    {
        var lstNumbers = new List<int>();
        for(var i = 1; i <= count; i++)
        {
            lstNumbers.Add(i);
        }
        return lstNumbers;
    }
    private static int[] GetSomeNumbers_Array()
    {
        var lstNumbers = new int[count];
        for (var i = 1; i <= count; i++)
        {
            lstNumbers[i-1] = i + 1;
        }
        return lstNumbers;
    }
    private static int[] GetSomeNumbers_Enumerable_Range()
    {
        return  Enumerable.Range(1, count).ToArray();
    }
    
    static void performance_100_Million()
    {
        var sw = new Stopwatch();
    
        sw.Start();
        var numbers1 = GetSomeNumbers_List_int();
        sw.Stop();
        //numbers1 = null;
        //GC.Collect();
        Console.WriteLine(String.Format("\"List<int>\" took {0} milliseconds", sw.ElapsedMilliseconds));
    
        sw.Reset();
        sw.Start();
        var numbers2 = GetSomeNumbers_Array();
        sw.Stop();
        //numbers2 = null;
        //GC.Collect();
        Console.WriteLine(String.Format("\"int[]\" took {0} milliseconds", sw.ElapsedMilliseconds));
    
        sw.Reset();
        sw.Start();
    //getting System.OutOfMemoryException in GetSomeNumbers_Enumerable_Range method
        var numbers3 = GetSomeNumbers_Enumerable_Range();
        sw.Stop();
        //numbers3 = null;
        //GC.Collect();
    
        Console.WriteLine(String.Format("\"int[]\" Enumerable.Range took {0} milliseconds", sw.ElapsedMilliseconds));
    }
    

    and I got OutOfMemoryException in GetSomeNumbers_Enumerable_Range method the only workaround is to deallocate the memory by:

    numbers = null;
    GC.Collect();
    
    0 讨论(0)
  • 2020-11-22 09:07

    If you are creating a lot of new System.Drawing.Bitmap objects, the Garbage Collector doesn't clear them. Eventually GDI+ will think you are running out of memory and will throw a "The parameter is not valid" exception. Calling GC.Collect() every so often (not too often!) seems to resolve this issue.

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

    I use GC.Collect only when writing crude performance/profiler test rigs; i.e. I have two (or more) blocks of code to test - something like:

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    TestA(); // may allocate lots of transient objects
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    TestB(); // may allocate lots of transient objects
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    ...
    

    So that TestA() and TestB() run with as similar state as possible - i.e. TestB() doesn't get hammered just because TestA left it very close to the tipping point.

    A classic example would be a simple console exe (a Main method sort-enough to be posted here for example), that shows the difference between looped string concatenation and StringBuilder.

    If I need something precise, then this would be two completely independent tests - but often this is enough if we just want to minimize (or normalize) the GC during the tests to get a rough feel for the behaviour.

    During production code? I have yet to use it ;-p

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

    If you are using a version of .net less than 4.5, manual collection may be inevitable (especially if you are dealing with many 'large objects').

    this link describes why:

    https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/

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