2010-06-11 21 views
6

me escribió este pequeño programa de prueba:uso de la memoria de cuerdas (o cualquier otro objeto) en .Net

using System; 

namespace GCMemTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      System.GC.Collect(); 

      System.Diagnostics.Process pmCurrentProcess = System.Diagnostics.Process.GetCurrentProcess(); 

      long startBytes = pmCurrentProcess.PrivateMemorySize64; 

      double kbStart = (double)(startBytes)/1024.0; 
      System.Console.WriteLine("Currently using " + kbStart + "KB."); 

      { 
       int size = 2000000; 
       string[] strings = new string[size]; 
       for(int i = 0; i < size; i++) 
       { 
        strings[i] = "blabla" + i; 
       } 
      } 

      System.GC.Collect(); 

      pmCurrentProcess = System.Diagnostics.Process.GetCurrentProcess(); 
      long endBytes = pmCurrentProcess.PrivateMemorySize64; 

      double kbEnd = (double)(endBytes)/1024.0; 
      System.Console.WriteLine("Currently using " + kbEnd + "KB."); 

      System.Console.WriteLine("Leaked " + (kbEnd - kbStart) + "KB."); 
      System.Console.ReadKey(); 
     } 
    } 
} 

La salida en la versión de lanzamiento es:

Currently using 18800KB. 
Currently using 118664KB. 
Leaked 99864KB. 

Asumo que el GC. la llamada de cobro eliminará las cadenas asignadas ya que salen del alcance, pero parece que no lo hace. No entiendo ni puedo encontrar una explicación para eso. Quizás alguien aquí?

Gracias, Alex

Respuesta

9

Se encuentra en el tamaño de la memoria privada - el montón administrado se han ampliado para dar cabida a las cuerdas, pero no va a liberar la memoria de vuelta al sistema operativo cuando las cuerdas están basura recolectada. En cambio, el montón administrado será más grande, pero tendrá mucho espacio libre, por lo que si crea más objetos, no requerirá que el montón se expanda.

Si desea ver la memoria utilizada dentro del montón administrado, consulte GC.GetTotalMemory. Tenga en cuenta que debido a la complejidad de la recolección de basura, hay una cierta cantidad de gangosidad en todo esto.

+0

¿Es cierto que llamar a 'GC.Collect' puede o no hacer una recolección de basura dependiendo de alguna variable oculta? –

+1

@Phil: No diría que se basa en una "variable oculta", pero no está garantizado que realmente haga la colección ahora. Es una solicitud en lugar de una orden, si se quiere. –

0

De hecho he usado el tamaño mem privada porque es la que está más cercana a la de explorador de procesos

si vuelvo a escribir el programa con el GC.GetTotalMemory así:

using System; 

namespace GCMemTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      System.GC.Collect(); 

      long startBytes = System.GC.GetTotalMemory(true); 

      { 
       string[] strings = new string[2000000]; 
       for (int i = 0; i < 2000000; i++) 
       { 
        strings[i] = "blabla" + i; 
       } 
       strings = null; 
      } 

      System.GC.Collect(); 

      long endBytes = System.GC.GetTotalMemory(true); 

      double kbStart = (double)(startBytes)/1024.0; 
      double kbEnd = (double)(endBytes)/1024.0; 

      System.Console.WriteLine("Leaked " + (kbEnd - kbStart) + "KB."); 
      System.Console.ReadKey(); 
     } 
    } 
} 

A continuación, la salida es:

Se filtró 0 KB.

Solo cuando tengo 'cadenas = nulo;' este es el caso, quítelo y pierdo 100MB. Esto significa que el alcance local en la rutina principal no hace que la matriz se libere. Si muevo esa parte en un método estático Test, y llamo a ese en su lugar, goteo unos pocos bytes. Creo que lo que debería aprender de esto es que los ámbitos locales son ignorados por el GC.

+0

¿Estaba corriendo bajo el depurador por casualidad? (¿Incluso en una compilación de lanzamiento?) Eso afecta a GC. –

+0

Lo tenía, pero sin él tiene el mismo resultado. – ava

Cuestiones relacionadas