Когда управляемый массив покидает область видимости, он помечается для сбора мусора. Если массив имеет тип значения, освобождение элементов происходит быстро, но не происходит до тех пор, пока массив не будет собран . Помните, byte
является типом значения, но byte[]
является ссылочным типом.
Вот краткий пример, который иллюстрирует:
void Main()
{
const int LOOPS = 5;
{
Console.WriteLine("When the arrays are kept inside the method's 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's 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)));
}
Вывод этого выглядит примерно так (точные результаты будут отличаться):
Когда массивы находятся внутри области действия метода:
Память GC: 24 576 232 байта (начальная память)
[1] Память GC: 45 002 324 байта (выделен локальный массив)
[2] Память GC: 44 845 548 байт (выделен локальный массив)
[3] Память GC: 64 574 296 байт (выделен локальный массив)
[4] Память GC: 64 959 472 байта (выделен локальный массив)
[5] Память GC: 44 675 340 байт (выделен локальный массив)
Память GC: 44 675 340 байт (вне локальной области)
Память GC: 24 347 296 байт (после запуска сбора GC)
Когда массивы находятся за пределами области действия метода:
Память GC: 24 355 488 байт (начальная память)
[1] Память GC: 44 467 612 байт (выделен массив)
[2] Память GC: 64 681 980 байт (выделен массив)
[3] Память GC: 85 493 004 байта (выделенный массив)
[4] Память GC: 104,442,028 байт (выделен массив)
[5] Память GC: 124 450 236 байт (выделен массив)
Память GC: 124 450 236 байт (вне локальной области)
Память GC: 124 357 588 байт (после запуска сбора GC)
Все области вышли:
Память GC: 124 365 780 байт (до запуска GC)
Память GC: 24 356 996 байт (после запуска сбора GC)
Чтобы решить вашу проблему:
- Убедитесь, что вы не цепляетесь за ссылки на
byte[]
s.
Байты не будут очищены, пока все ссылки на массив не будут
ушел, и это полностью выходит за рамки.
- Явно вызовите
GC.Collect()
после того, как вы покинете область действия байтового массива. однажды
byte[]
очистится сам по себе, но вы можете
скажи ему бежать вместо ожидания.