2010-06-22 9 views
12

Ejecutar una aplicación .NET en Windows Server 2008 x64 con 16 GB de RAM. Esta aplicación necesita buscar y analizar una gran cantidad de datos (aproximadamente 64 GB), y mantener todo en la memoria a la vez.Recolector de elementos no utilizados .NET y memoria virtual x64

Lo que espero ver: El tamaño del proceso se expande más allá de 16GB a 64GB. Windows usa memoria virtual para enviar los datos extra a/desde el disco según sea necesario. Este es el clásico caso de uso de la memoria virtual.

Lo que realmente veo: El tamaño del proceso está limitado a la cantidad de memoria física (16 GB). La aplicación pasa el 99.8% de su tiempo en el recolector de basura.

¿Por qué nuestra aplicación no puede utilizar la memoria virtual? ¿Es esto un problema en la configuración del recolector de basura .NET o en el administrador de memoria virtual x64 de Windows mismo? ¿Qué puedo hacer para que nuestra aplicación use memoria virtual en lugar de limitarse a la memoria física?

Gracias.

- Brian

Actualización: Me han escrito un programa muy pequeño que presenta el mismo comportamiento:

using System; 

namespace GCTest 
{ 
    class Program 
    { 
     static void Main() 
     { 
      byte[][] arrays = new byte[100000000][]; 
      for (int i = 0; i < arrays.Length; ++i) 
      { 
       arrays[i] = new byte[320]; 
       if (i % 100000 == 0) 
       { 
        Console.WriteLine("{0} arrays allocated", i); 
        System.Threading.Thread.Sleep(100); 
       } 
      } 
     } 
    } 
} 

Si quieres probarlo, asegúrese de construir para x64. Puede que tenga que modificar las constantes un poco para estresar su sistema. El comportamiento que veo es que el proceso se atasca a medida que se acerca a un tamaño de 16 GB. No hay mensaje de error o excepción lanzada. El monitor de rendimiento informa que el% del tiempo de CPU en GC se aproxima al 100%.

¿No es esto inaceptable? ¿Dónde está el sistema de memoria virtual?

+0

¿Qué está utilizando para determinar el tamaño del proceso? (Eliminemos las opciones fáciles primero :)) – Paolo

+0

"Tamaño de confirmación" desde el Administrador de tareas de Windows. También se usa "# Total de bytes comprometidos" en el Monitor de rendimiento. Estoy bastante seguro de que estoy midiendo el tamaño de la memoria virtual del proceso en lugar de su conjunto de trabajo físico. – brianberns

+0

¿Puedo preguntar lo obvio? ¿Realmente necesita cargar todo esto en la memoria a la vez? ¿Es posible tomar otro enfoque y hacer algún tipo de paginación manual por su cuenta? – CodingGorilla

Respuesta

2

Parece que no está manteniendo una referencia a los datos de gran tamaño. El recolector de basura no recogerá objetos referenciados.

+0

No creo que eso sea relevante. Ninguno de los datos es en realidad basura, todo está referenciado. Por lo tanto, no espero que el GC recolecte ningún tipo de memoria. Parece que el GC consume el 100% de la CPU porque el proceso se ha quedado sin memoria física y .NET está tratando de liberar algunos.Sin embargo, no hay nada que liberar, idealmente, el proceso debería expandirse usando memoria virtual en lugar de gastar todo su tiempo en el GC tratando de liberar objetos (no existentes) no utilizados. – brianberns

+0

Si está asignando 64 GB de datos, pero solo 16 GB están asignados, entonces el resto no está referenciado y ha sido sometido a GC. A menos que no entienda tu pregunta. –

+0

No entiende la pregunta. Estoy tratando de asignar 64 GB de datos, pero el proceso se atasca después de que solo he asignado 16 GB de datos. Nunca tengo la oportunidad de asignar el resto de los datos. – brianberns

10

¿Ha comprobado para asegurarse de que su archivo de paginación está configurado para que pueda expandirse a ese tamaño?

actualización

He estado jugando con esto un poco con el ejemplo dado, y esto es lo que veo.

Sistema: Windows 7 64bit, 6 GB de RAM de triple canal, 8 núcleos.

  1. Necesita un archivo de paginación adicional en otro eje desde su SO o este tipo de investigación manguera su máquina. Si todo está peleando por el mismo archivo de paginación, empeora las cosas.

  2. Veo una gran cantidad de datos promovidos de generación en generación en el GC, más una gran cantidad de GC sweeps \ collections y una gran cantidad de fallas de página como resultado de los límites de la memoria física. Solo puedo suponer que cuando la memoria física se agote \ muy alta, esto desencadena barridos y promociones de generación, lo que provoca que se toque una gran cantidad de memoria paginada que conduce a un spriral de muerte a medida que se localiza la memoria tocada y otra memoria es forzado a salir. Todo termina en un desastre húmedo. Esto parece ser inevitable cuando se asigna una gran cantidad de objetos de larga vida que terminan en el Heap Small Object Heap.

Ahora comparar esto con la asignación de objetos de una manera destinará directamente en el montón de objetos grandes (que no sufre los mismos problemas de barrido y de promoción):

private static void Main() 
{ 
    const int MaxNodeCount = 100000000; 
    const int LargeObjectSize = (85 * 1000); 

    LinkedList<byte[]> list = new LinkedList<byte[]>(); 

    for (long i = 0; i < MaxNodeCount; ++i) 
    { 
     list.AddLast(new byte[LargeObjectSize]); 

     if (i % 100000 == 0) 
     { 
      Console.WriteLine("{0:N0} 'approx' extra bytes allocated.", 
       ((i + 1) * LargeObjectSize)); 
     } 
    } 
} 

Esto funciona como decir esperada la memoria virtual se usa y luego se agota: 54 GB en mi entorno \ configuración.

Parece que la asignación de una masa de objetos pequeños de vida larga eventualmente conducirá a un círculo vicioso en el GC ya que las barridas de generación y las promociones se realizan cuando se agotó la memoria física: es una espiral de muerte de archivo de página.

Actualización 2

Mientras que investiga el problema que jugaba con una serie de opciones \ configuraciones que no hizo ninguna diferencia apreciable:

  • Forzar el modo GC servidor.
  • Configurando GC de baja latencia.
  • Varias combinaciones de forzar GC para intentar amortizar GC.
  • Conjuntos de trabajo de proceso Min \ Max.
+0

No, pero ¿no debería el administrador de memoria virtual de Windows iniciar automáticamente la búsqueda, al menos hasta cierto punto después de 16 GB? ¿De qué sirve tener memoria virtual si está limitada por la cantidad de memoria física? – brianberns

+0

Es configurable, vale la pena verificarlo. Los problemas pueden variar desde una política inesperada hasta una chispa brillante que desactiva la búsqueda. –

+0

OK, aumenté el archivo de paginación a 30GB, pero no tuvo ningún efecto. Creo que el recolector de basura .NET me impide asignar más de 16 GB de objetos, por lo que el sistema de memoria virtual de Windows nunca tiene la posibilidad de iniciar la búsqueda. – brianberns

Cuestiones relacionadas