Molto grande collezione in .NET causa eccezioni out-of-memory
-
01-10-2019 - |
Domanda
sto testando quanto grande una collezione potrebbe essere in .Net. Tecnicamente, qualsiasi oggetto di raccolta potrebbe cresce la dimensione della memoria fisica.
Poi ho provato il seguente codice in un sever, che ha una memoria da 16 GB, in esecuzione Windows Server 2003 e Visual Studio 2008. Ho testato sia F # e C # codice, e guardò il Task Manager durante l'esecuzione. Vedo che dopo circa crescere 2GB di memoria, il programma si è schiantato con out-of-memory eccezione. Io ho impostato la piattaforma di destinazione per x64 nella pagina delle proprietà.
open System.Collections.Generic
let d = new Dictionary<int, int>()
for i=1 to 1000000000 do
d.Add(i,i)
Ho fatto una stessa prova al href="http://www.itu.dk/research/c5/" rel="noreferrer"> C5 biblioteca raccolta . Il risultato è che il dizionario in C5 potrebbe utilizzare l'intera memoria. Il codice utilizza C5:
let d = C5.HashDictionary<int, int> ()
for i=1 to 1000000000 do
d.Add(i,i)
Chiunque sa perché?
Soluzione
La Microsoft CLR ha un limite di 2 GB dimensione massima oggetto, anche la versione a 64 bit. (Non sono sicuro se questo limite è presente anche in altre implementazioni, come Mono.)
La limitazione si applica a ciascuno singola oggetto - non la dimensione totale di tutti gli oggetti -. Che significa che è relativamente facile soluzione, utilizzando un insieme composito di qualche tipo
C'è una discussione e qualche esempio di codice qui ...
Sembra che ci sia ben poco documentazione ufficiale che si riferisce a questo limite. Si tratta, dopo tutto, solo un dettaglio di implementazione del CLR corrente. L'unica menzione che io sappia è in questa pagina :
Quando si esegue una a 64 bit gestito applicazione su Windows a 64 bit sistema operativo, è possibile creare un oggetto di non più di 2 gigabyte (GB).
Altri suggerimenti
Nelle versioni di NET precedenti a 4,5, la dimensione massima dell'oggetto è 2GB. Da 4.5 in poi è possibile allocare oggetti più grandi, se gcAllowVeryLargeObjects è abilitata. Si noti che il limite per string
non è interessato, ma di "matrici" dovrebbe coprire "liste", in quanto anche le liste sono supportati da matrici.
E per essere chiari, un dizionario utilizza un singolo array di aggiungere le coppie. E 'cresciuto (raddoppiato?) Ogni volta che è pieno. Quando ci sono 512 milioni di oggetti, la sua dimensione è 2GByte (con un puntatore di oggetto a 32 bit, e supponendo perfetta distribuzione). Aggiunta di un elemento in più rende il dizionario cercare di raddoppiare nuovamente la dimensione della matrice. Boom.
Il C5 HashDictionary utilizza hashing lineare, e probabilmente usa un array di benne ogni multiplo contenente (16?) Elementi. Dovrebbe funzionare nello stesso problema (molto) più tardi.
Il "Consenti oggetti di grandi dimensioni" solo aiuterà a sbarazzarsi di eccezione OOM.
Quando si ha la necessità di immagazzinare moltissimi oggetti che il problema che si vede è GC stalle (pausa). Quello che abbiamo fatto è "nascosto" dei dati da GC, che si trasformò in una soluzione molto pratica.
Vedere questo: https://www.infoq.com/articles/ Big-memoria-Part-3
È possibile utilizzare la cache che funziona come un dizionario: https://github.com/aumcode/nfx/tree/ master / sorgente / NFX / ApplicationModel / Pile
vedi la sezione caching