Cuando una matriz administrada sale del alcance, se marca para la recolección de elementos no utilizados. Si la matriz es de un tipo de valor, la desasignación de elementos es rápida, pero no ocurre hasta que la matriz se recopile. Recuerde, byte
es un tipo de valor pero byte[]
es un tipo de referencia.
Aquí hay una muestra rápida que ilustra:
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)));
}
La salida de este se ve algo como esto (resultados exactos variarán):
Cuando las matrices se mantienen dentro del alcance del método:
Memoria del GC: 24,576,232 bytes (memoria inicial)
[1] Memoria del GC: 45,002,324 bytes (matriz local asignada)
[2] GC memoria: 44,845,548 bytes (array local asignado)
[3] GC memoria: 64,574,296 bytes (array local asignado)
[4] Memoria GC: 64,959,472 bytes (array local asignado)
[5] memoria GC: 44,675,340 bytes (array local asignado)
GC memoria: 44,675,340 bytes (ámbito local salido)
GC memoria: 24,347,296 bytes (después de la recogida GC RAN)
Cuando las matrices están fuera del alcance del método:
GC memoria: 24,355,488 bytes (de memoria inicial)
[1] GC de memoria: 44,467,612 bytes (array asignado)
[2] Memoria GC : 64,681,980 bytes (array asignados)
[3] GC de memoria: 85,493,004 bytes (array asignado)
[4] de memoria GC: 104,442,028 bytes (array asignado)
[5] GC de memoria: 124,450,236 bytes (array asignado)
GC memoria: 124,450,236 bytes (salido de ámbito local)
GC memoria: 124,357,588 bytes (después de la recolección GC corrió)
Todos los ámbitos salieron:
GC Memoria: 124,365,780 bytes (antes de que se ejecute GC)
GC memoria: 24,356,996 bytes (después corrió colección GC)
Para resolver el problema:
- Asegúrese de que no se aferran a cualquier referencia a los
byte[]
s. Los bytes no se borrarán hasta que todas las referencias a la matriz hayan desaparecido y esté completamente fuera del alcance.
- Llamar explícitamente al
GC.Collect()
después de que haya abandonado el alcance de la matriz de bytes.Una vez que está fuera de alcance, byte[]
se borrará por sí solo pero puede indicarle que se ejecute en lugar de esperar.
Respecto a su comentario a Amadan: ¿Dónde se declara su variable? ¿Dentro del método del evento en el mensaje recibido o globalmente en tu clase, algoclase? – Markus