When the managed array leaves its scope, it becomes marked for garbage collection. If the array is of type value, the release of elements occurs quickly, but does not occur until the array is assembled. Remember that byte is a value type, but byte[] is a reference type.
Here is an example that shows:
void Main() { const int LOOPS = 5; { Console.WriteLine("When the arrays are kept inside the method scope:"); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (starting memory)", GC.GetTotalMemory(false))); for(int i = 0; i < LOOPS; i++) this.AllocateArray(i); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (exited local scope)", GC.GetTotalMemory(false))); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (after GC collection ran)", GC.GetTotalMemory(true))); Console.WriteLine("\nWhen the arrays are outside the method scope:"); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (starting memory)", GC.GetTotalMemory(false))); var arrays = new byte[LOOPS][]; for(int i = 0; i < LOOPS; i++) this.AllocateArray(i, arrays); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (exited local scope)", GC.GetTotalMemory(false))); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (after GC collection ran)", GC.GetTotalMemory(true))); arrays[0][0] = 1; // Prevent the arrays from being optimized away } Console.WriteLine("\nAll scopes exited:"); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (before GC runs)", GC.GetTotalMemory(false))); Console.WriteLine(String.Format(" GC Memory: {0:N0} bytes (after GC collection ran)", GC.GetTotalMemory(true))); } public void AllocateArray(int run) { var array = new byte[20000000]; Thread.Sleep(100); // Simulate work.. Console.WriteLine(String.Format("[{0}] GC Memory: {1:N0} bytes (local array allocated)", run+1, GC.GetTotalMemory(false))); array[0] = 1; // Prevent the array from being optimized away } public void AllocateArray(int run, byte[][] arrays) { arrays[run] = new byte[20000000]; Thread.Sleep(100); // Simulate work.. Console.WriteLine(String.Format("[{0}] GC Memory: {1:N0} bytes (array allocated)", run+1, GC.GetTotalMemory(false))); }
The result from this looks something like this (the exact results will vary):
When arrays are stored inside the method area: GC memory: 24,576,232 bytes (initial memory)
[1] GC memory: 45 002 324 bytes (local array allocated)
[2] GC memory: 44,845,548 bytes (local array allocated)
[3] GC memory: 64,574,296 bytes (local array allocated)
[4] GC memory: 64,959,472 bytes (local array allocated)
[5] GC memory: 44,675,340 bytes (local array allocated) GC memory: 44,675,340 bytes (leaving the local area) GC Memory: 24,347,296 bytes (after starting the GC collection)
When arrays are outside the scope of the method: GC-memory: 24 355 488 bytes (initial memory)
[1] GC memory: 44,467,612 bytes (dedicated matrix)
[2] GC Memory: 64,681,980 bytes (array allocation)
[3] GC memory: 85,493,004 bytes (allocated by array)
[4] GC memory: 104,442,028 bytes (dedicated matrix)
[5] GC memory: 124,450,236 bytes (array allocated) GC memory: 124,450,236 bytes (leaving the local area) GC Memory: 124 357 588 bytes (after starting the GC collection)
All output areas: GC Memory: 124,365,780 bytes (before starting the GC) GC: 24,356,996 bytes (after starting the GC collection)
To solve your problem:
- Make sure that you do not match links to
byte[] s. Bytes will not be cleared until all array references are complete and it is completely out of scope. - Call
GC.Collect() explicitly after you leave the byte array area. once it goes out of scope, byte[] will clear itself, but you can tell it to execute instead of waiting.