Come probabilmente hai capito, il problema è che stai cercando di allocare un grande blocco contiguo di memoria, che non funziona a causa della frammentazione della memoria. Se avessi bisogno di fare quello che stai facendo, farei quanto segue:
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];
}
Quindi, per ottenere un particolare indice che useresti randomNumbers[i / sizeB][i % sizeB]
.
Un'altra opzione se si accede sempre ai valori in ordine potrebbe essere quella di utilizzare il costruttore sovraccarico per specificare il seme. In questo modo otterresti un numero semi casuale (come il DateTime.Now.Ticks
) memorizzarlo in una variabile, quindi ogni volta che inizi a scorrere l'elenco creerai una nuova istanza casuale utilizzando il seme originale:
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 notare che mentre il blog collegato nella risposta di Fredrik Mörk indica che il problema è solitamente dovuto alla mancanza di spazio degli indirizzi , non elenca una serie di altri problemi, come la limitazione delle dimensioni degli oggetti CLR da 2 GB (menzionata in un commento da ShuggyCoUk sullo stesso blog), sorvola sulla frammentazione della memoria e non menziona l'impatto della dimensione del file di pagina (e come può essere affrontato con l'uso della CreateFileMapping
funzione ).
La limitazione di 2 GB significa che randomNumbers
deve essere inferiore a 2 GB. Poiché gli array sono classi e hanno un po 'di overhead, ciò significa che un array di double
dovrà essere più piccolo di 2 ^ 31. Non sono sicuro di quanto dovrebbe essere più piccola di 2 ^ 31 la lunghezza, ma il sovraccarico di un array .NET? indica 12-16 byte.
La frammentazione della memoria è molto simile alla frammentazione dell'HDD. Potresti avere 2 GB di spazio degli indirizzi, ma quando crei e distruggi gli oggetti ci saranno degli spazi tra i valori. Se questi spazi sono troppo piccoli per il tuo oggetto di grandi dimensioni e non è possibile richiedere spazio aggiuntivo, otterrai il fileSystem.OutOfMemoryException
. Ad esempio, se crei 2 milioni di oggetti da 1024 byte, stai utilizzando 1,9 GB. Se elimini ogni oggetto in cui l'indirizzo non è un multiplo di 3, utilizzerai 0,6 GB di memoria, ma verrà distribuito nello spazio degli indirizzi con blocchi aperti di 2024 byte in mezzo. Se hai bisogno di creare un oggetto che era .2GB non saresti in grado di farlo perché non c'è un blocco abbastanza grande per adattarlo e non è possibile ottenere spazio aggiuntivo (supponendo un ambiente a 32 bit). Possibili soluzioni a questo problema sono cose come l'utilizzo di oggetti più piccoli, la riduzione della quantità di dati archiviati in memoria o l'utilizzo di un algoritmo di gestione della memoria per limitare / prevenire la frammentazione della memoria. Va notato che, a meno che non si stia sviluppando un programma di grandi dimensioni che utilizza una grande quantità di memoria, questo non sarà un problema. Anche,
Poiché la maggior parte dei programmi richiede memoria di lavoro dal sistema operativo e non richiede una mappatura dei file, saranno limitati dalla RAM del sistema e dalle dimensioni del file di paging. Come notato nel commento di Néstor Sánchez (Néstor Sánchez) sul blog, con codice gestito come C # sei bloccato alla limitazione della RAM / file di pagina e allo spazio degli indirizzi del sistema operativo.
Era molto più lungo del previsto. Si spera che aiuti qualcuno. L'ho pubblicato perché mi sono imbattuto System.OutOfMemoryException
nell'esecuzione di un programma x64 su un sistema con 24 GB di RAM anche se il mio array conteneva solo 2 GB di materiale.