When I put this code in a small Console project:
Console.WriteLine($"Mémoire avant allocation 1G: {GC.GetTotalMemory(false)}");
byte[] buf = new byte[1000000000];
Console.WriteLine($"Mémoire après allocation 1G: {GC.GetTotalMemory(false)}");
buf = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine($"Mémoire après libération 1G: {GC.GetTotalMemory(false)}");
I get the Following result (as expected):
Mémoire avant allocation 1G: 30028 Mémoire après allocation 1G: 1000038252 Mémoire après libération 1G: 29472
Now the very same code in the big Application I'm working on, I get this result:
Mémoire avant allocation 1G: 153152496 Mémoire après allocation 1G: 1153152552 Mémoire après libération 1G: 1146813960
As you can see, GC.Collect
does nothing here.
Why is that?
Try compacting the LOH
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect( );
Also note that the documentation describing GC.Collect( )
always uses the word "tries" or "try".
Example (emphasis mine):
Use this method to try to reclaim all memory that is inaccessible. It performs a blocking garbage collection of all generations.
All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory.