GC.Collect
The C# language is a garbage-collected language. This means that memory that is no longer referenced by your program will be reclaimed and is later reused.
With GC.Collect
, we force a garbage collection to occur at any time. This might seem like a good idea, but it almost is not. It interferes with performance.
Three calls to get the total memory usage on the system are present. They occur before the allocation, after the allocation, and after the forced garbage collection.
using System; class Program { static void Main() { long mem1 = GC.GetTotalMemory(false); { // Allocate an array and make it unreachable. int[] values = new int[50000]; values = null; } long mem2 = GC.GetTotalMemory(false); { // Collect garbage. GC.Collect(); } long mem3 = GC.GetTotalMemory(false); { Console.WriteLine(mem1); Console.WriteLine(mem2); Console.WriteLine(mem3); } } }45664 245696 33244
CollectionCount
This method tells us how many times garbage collection has occurred. Getting information about how often garbage collection is occurring is not always simple.
CollectionCount
and the GC.MaxGeneration
property, we get this information.using System; class Program { static void Main() { // This loop does a lot of allocations! for (int i = 0; i < 100; i++) { for (int a = 0; a < 1000; a++) { System.IO.Path.GetRandomFileName(); System.IO.Path.GetRandomFileName(); } System.Threading.Thread.Sleep(1); } // Display collection counts. for (int i = 0; i <= GC.MaxGeneration; i++) { int count = GC.CollectionCount(i); Console.WriteLine(count); } } }15 0 0
GetTotalMemory
This returns the number of bytes allocated. It accesses statistics about the managed heap. It returns data about the entire .NET Framework, not the specific program.
bool
, which lets you demand a garbage collection to occur before taking the numbers.bool
to GC.GetTotalMemory
. False indicates that an expensive collection should not be forced.using System; class Program { static void Main() { long bytes1 = GC.GetTotalMemory(false); // Get memory in bytes byte[] memory = new byte[1000 * 1000 * 10]; // Ten million bytes memory[0] = 1; // Set memory (prevent allocation from being optimized out) long bytes2 = GC.GetTotalMemory(false); // Get memory long bytes3 = GC.GetTotalMemory(true); // Get memory Console.WriteLine(bytes1); Console.WriteLine(bytes2); Console.WriteLine(bytes2 - bytes1); // Write difference Console.WriteLine(bytes3); Console.WriteLine(bytes3 - bytes2); // Write difference Console.ReadLine(); } }21060 Program started with these bytes. 10021092 After ten million bytes allocated. 10000032 Difference. 12860 After garbage collection. -10008232 Difference.
The GC.GetTotalMemory
method operates on the concept of the managed heap, not the program that you are calling it from.
GC.GetTotalMemory
, you will be counting the allocations from all the mutator programs.So when should you call GC.Collect
? In my experience, you should never call it. The call will usually not do much to reduce overall memory usage.
GC.Collect
on one application will cause a performance hit on all web sites in the same pool.Here is a way to monitor memory use. You can set up a special web page or dialog in your program that reports the statistics from GetTotalMemory
.
static
field, and then subtract the second from the first to see the change.GC.Collect
is best used for diagnostics purposes (like determining a baseline of memory usage). Memory management is best left to the .NET Framework itself when possible.