2010-09-07 10 views
31

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.La colección muy grande en .Net causa la excepción de falta de memoria

Luego probé el siguiente código en un servidor que tiene 16 GB de memoria, ejecutando Windows 2003 Server 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 aumentar la memoria de 2GB, el programa se bloqueó con la excepción de falta de memoria. Establecí la plataforma objetivo en x64 en la página de propiedades.

open System.Collections.Generic 

let d = new Dictionary<int, int>() 

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

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

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

¿Alguien sabe por qué?

+12

memoria física no tiene nada que ver con tamaños máximos. Windows ha utilizado la gestión de memoria virtual durante más de una década. Puede tener objetos que son mucho, mucho más grandes que la memoria física disponible porque, por supuesto, la memoria física disponible podría ser * cero * cuando se crea un nuevo proceso. Ese es el * punto * completo de la memoria virtual; esa memoria física es solo una optimización del rendimiento de la memoria virtual. (Si no hay suficiente memoria física para contener el conjunto de trabajo, el rendimiento se degrada, pero todo debería funcionar aún *.) –

+2

@EricLippert Entendido y aceptado, pero ¿qué pasa con el reverso? ¿Alguna vez recibirás un OOM cuando hay memoria física? ¿disponible? (suponiendo que es un OOM real no demasiados controladores/problema similar). En este caso, parece que el límite fue un límite impuesto por CLR, pero eso solo significa que la pregunta de OP es buena, en mi opinión – Basic

Respuesta

42

El CLR de Microsoft tiene un límite de tamaño de objeto máximo 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 simple, no el tamaño total de todos los objetos, lo que significa que es relativamente fácil a la solución utilizando una colección compuesta de algún tipo.

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

Parece que hay muy poca documentación oficial que se refiere a este límite. Es, después de todo, solo un detalle de implementación del CLR actual. La única mención que yo sepa es on this page:

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

+0

+1, @Yin: este artículo podría ayudarlo a moverse, http: // blogs. msdn.com/b/joshwil/archive/2005/08/10/1050202.aspx –

+0

@KMan: Ha. Lo edité en solo un par de segundos antes de que tu comentario apareciera :) – LukeH

+1

Y toda tu publicación acaba de llegar un par de segundos antes que la mía :) –

10

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 HashDictionary C5 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.

+0

¡Buen comentario! Gracias. –

+0

Por cierto, la implementación en c5 es de cadena lineal: para cada valor de hash, es una lista vinculada. –

+0

Ah, gracias. Los consejos de papel hashing lineales originales contra eso. –

18

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 string no se ve afectado, pero las "matrices" también deberían abarcar "listas", ya que las listas están respaldadas por matrices.

-1

"Permitir objetos grandes" solo ayudará a deshacerse de la excepción OOM.

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

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

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

ver la sección de almacenamiento en caché

Cuestiones relacionadas