Como probablemente se habrá dado cuenta, el problema es que está intentando asignar un bloque grande de memoria contiguo, que no funciona debido a la fragmentación de la memoria. Si tuviera que hacer lo que estás haciendo, haría lo siguiente:
int sizeA = 10000,
sizeB = 10000;
double sizeInMegabytes = (sizeA * sizeB * 8.0) / 1024.0 / 1024.0; //762 mb
double[][] randomNumbers = new double[sizeA][];
for (int i = 0; i < randomNumbers.Length; i++)
{
randomNumbers[i] = new double[sizeB];
}
Luego, para obtener un índice particular, usaría randomNumbers[i / sizeB][i % sizeB]
.
Otra opción si siempre accede a los valores en orden podría ser utilizar el constructor sobrecargado para especificar la semilla. De esta manera, obtendría un número semi aleatorio (como el DateTime.Now.Ticks
) almacenarlo en una variable, luego, cuando comience a revisar la lista, creará una nueva instancia aleatoria utilizando la semilla original:
private static int randSeed = (int)DateTime.Now.Ticks; //Must stay the same unless you want to get different random numbers.
private static Random GetNewRandomIterator()
{
return new Random(randSeed);
}
Es importante tener en cuenta que, si bien el blog vinculado en la respuesta de Fredrik Mörk indica que el problema generalmente se debe a la falta de espacio de direcciones , no enumera una serie de otros problemas, como la limitación de tamaño del objeto CLR de 2GB (mencionado en un comentario de ShuggyCoUk en el mismo blog), pasa por alto la fragmentación de la memoria y no menciona el impacto del tamaño del archivo de página (y cómo se puede abordar con el uso de la CreateFileMapping
función ).
La limitación de 2 GB significa que randomNumbers
debe ser inferior a 2 GB. Dado que las matrices son clases y tienen algo de sobrecarga en sí mismas, esto significa que una matriz double
deberá ser más pequeña que 2 ^ 31. No estoy seguro de cuánto más pequeño que 2 ^ 31 tendría que ser la longitud, pero ¿la sobrecarga de una matriz .NET? indica 12-16 bytes.
La fragmentación de la memoria es muy similar a la fragmentación del disco duro. Es posible que tenga 2 GB de espacio de direcciones, pero a medida que crea y destruye objetos, habrá espacios entre los valores. Si estos espacios son demasiado pequeños para su objeto grande, y no se puede solicitar espacio adicional, obtendrá elSystem.OutOfMemoryException
. Por ejemplo, si crea 2 millones de objetos de 1024 bytes, entonces está utilizando 1,9 GB. Si elimina todos los objetos en los que la dirección no es un múltiplo de 3, utilizará 0,6 GB de memoria, pero se distribuirá por todo el espacio de direcciones con bloques abiertos de 2024 bytes en el medio. Si necesita crear un objeto de 0,2 GB, no podrá hacerlo porque no hay un bloque lo suficientemente grande para que quepa y no se puede obtener espacio adicional (asumiendo un entorno de 32 bits). Las posibles soluciones a este problema son cosas como el uso de objetos más pequeños, la reducción de la cantidad de datos que almacena en la memoria o el uso de un algoritmo de administración de memoria para limitar / prevenir la fragmentación de la memoria. Cabe señalar que, a menos que esté desarrollando un programa grande que use una gran cantidad de memoria, esto no será un problema. También,
Dado que la mayoría de los programas solicitan memoria de trabajo del sistema operativo y no solicitan una asignación de archivos, estarán limitados por la RAM del sistema y el tamaño del archivo de página. Como se señala en el comentario de Néstor Sánchez (Néstor Sánchez) en el blog, con código administrado como C # estás pegado a la limitación de RAM / archivo de página y al espacio de direcciones del sistema operativo.
Eso fue mucho más largo de lo esperado. Ojalá ayude a alguien. Lo publiqué porque encontré la System.OutOfMemoryException
ejecución de un programa x64 en un sistema con 24 GB de RAM a pesar de que mi matriz solo contenía 2 GB de material.