Una colección muy grande en .Net provoca una excepción de falta de memoria

Estoy probando qué tan grande podría ser una colección en .Net. Técnicamente, cualquier objeto de colección podría crecer al tamaño de la memoria física.

Luego probé el siguiente código en un servidor que tiene 16GB de memoria, ejecutando el servidor de Windows 2003 y Visual Studio 2008. Probé tanto el código F # como el código C # y miré al Administrador de tareas mientras estaba en ejecución. Puedo ver que después de boost la memoria de 2GB, el progtwig se bloqueó con la excepción de falta de memoria. Establecí la plataforma objective en x64 en la página de propiedades.

open System.Collections.Generic let d = new Dictionary() for i=1 to 1000000000 do d.Add(i,i) 

Hice la misma prueba a la biblioteca de colección C5 . El resultado es que el diccionario en C5 podría agotar toda la memoria. El código usa C5:

 let d = C5.HashDictionary () for i=1 to 1000000000 do d.Add(i,i) 

Alguien sabe por qué?

Microsoft CLR tiene un límite máximo de tamaño de objeto de 2 GB, incluso la versión de 64 bits. (No estoy seguro de si este límite también está presente en otras implementaciones, como Mono.)

La limitación se aplica a cada objeto individual , no al tamaño total de todos los objetos, lo que significa que es relativamente fácil solucionarlo utilizando una colección compuesta de algún tipo.

Hay una discusión y un código de ejemplo aquí …

  • BigArray , superando el límite de tamaño de matriz de 2 GB

Parece que hay muy poca documentación oficial que se refiera a este límite. Es, después de todo, solo un detalle de implementación del CLR actual. La única mención que conozco es en esta página :

Cuando ejecuta una aplicación administrada de 64 bits en un sistema operativo Windows de 64 bits, puede crear un objeto de no más de 2 gigabytes (GB).

En las versiones de .NET anteriores a 4.5, el tamaño máximo del objeto es de 2 GB. A partir de 4.5, puede asignar objetos más grandes si está habilitado gcAllowVeryLargeObjects . Tenga en cuenta que el límite para la string no se ve afectado, pero las “matrices” también deberían cubrir las “listas”, ya que las listas están respaldadas por matrices.

Y para ser claros, un diccionario usa una sola matriz para agregar los pares. Se cultiva (¿se dobla?) Cada vez que está lleno. Cuando hay 512 millones de objetos, su tamaño es de 2 GByte (con un puntero de objeto de 32 bits y suponiendo una distribución perfecta). Agregar un elemento más hace que el diccionario intente duplicar el tamaño de la matriz nuevamente. Auge.

El C5 HashDictionary utiliza hash lineal, y probablemente utiliza una matriz de cubos que contienen cada uno elementos múltiples (16?). Debería encontrarse con el mismo problema (mucho) más tarde.

El “permitir objetos grandes” solo ayudará a deshacerse de la excepción OOM.

Cuando uno necesita almacenar muchos objetos, el problema que verá es que el GC se detiene (hace una pausa). Lo que hemos hecho es “ocultar” los datos de GC, lo que se convirtió en una solución muy práctica.

Vea esto: https://www.infoq.com/articles/Big-Memory-Part-3

Puede usar el caché que funciona como diccionario: https://github.com/aumcode/nfx/tree/master/Source/NFX/ApplicationModel/Pile

ver la sección de almacenamiento en caché