Como você provavelmente percebeu, o problema é que você está tentando alocar um grande bloco contíguo de memória, que não funciona devido à fragmentação da memória. Se eu precisasse fazer o que você está fazendo, faria o seguinte:
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];
}
Então, para obter um índice específico, você usaria randomNumbers[i / sizeB][i % sizeB]
.
Outra opção se você sempre acessar os valores em ordem pode ser usar o construtor sobrecarregado para especificar a semente. Dessa forma, você obteria um número semi-aleatório (como o DateTime.Now.Ticks
) e o armazenaria em uma variável, então sempre que começar a examinar a lista, você criaria uma nova instância Random usando a semente 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);
}
É importante notar que, embora o blog com link na resposta de Fredrik Mörk indique que o problema geralmente é devido à falta de espaço de endereço, ele não lista uma série de outros problemas, como a limitação de tamanho do objeto CLR de 2 GB (mencionado em um comentário de ShuggyCoUk no mesmo blog), ignora a fragmentação da memória e não menciona o impacto do tamanho do arquivo de página (e como ele pode ser tratado com o uso da CreateFileMapping
função ).
A limitação de 2 GB significa que randomNumbers
deve ser inferior a 2 GB. Como os arrays são classes e têm alguma sobrecarga, isso significa que um array de double
precisará ser menor que 2 ^ 31. Não tenho certeza de quanto menor então 2 ^ 31 o comprimento teria que ser, mas sobrecarga de um array .NET? indica 12 - 16 bytes.
A fragmentação da memória é muito semelhante à fragmentação do HDD. Você pode ter 2 GB de espaço de endereço, mas conforme você cria e destrói objetos, haverá lacunas entre os valores. Se essas lacunas forem muito pequenas para o seu objeto grande e não for possível solicitar espaço adicional, você obterá oSystem.OutOfMemoryException
. Por exemplo, se você criar objetos de 2 milhões e 1.024 bytes, estará usando 1,9 GB. Se você excluir todos os objetos em que o endereço não for um múltiplo de 3, você usará 0,6 GB de memória, mas ela estará espalhada pelo espaço de endereço com blocos abertos de 2024 bytes entre eles. Se você precisar criar um objeto com .2 GB, você não poderá fazê-lo porque não há um bloco grande o suficiente para caber nele e não é possível obter espaço adicional (assumindo um ambiente de 32 bits). As soluções possíveis para esse problema são coisas como usar objetos menores, reduzir a quantidade de dados que você armazena na memória ou usar um algoritmo de gerenciamento de memória para limitar / evitar a fragmentação da memória. Deve-se observar que, a menos que você esteja desenvolvendo um programa grande que usa uma grande quantidade de memória, isso não será um problema. Além disso,
Como a maioria dos programas requer memória de trabalho do sistema operacional e não solicita um mapeamento de arquivo, eles serão limitados pela RAM do sistema e pelo tamanho do arquivo de página. Conforme observado no comentário de Néstor Sánchez (Néstor Sánchez) no blog, com código gerenciado como C # você fica preso à limitação do arquivo RAM / página e ao espaço de endereço do sistema operacional.
Isso foi muito mais longo do que o esperado. Espero que ajude alguém. Eu postei porque corri para System.OutOfMemoryException
rodar um programa x64 em um sistema com 24 GB de RAM, embora meu array tivesse apenas 2 GB de material.