2011-12-02 10 views
8

TDictionary<TKey,TValue> usa un array interno che viene raddoppiata se è pieno:Come evitare di esaurire la memoria con un TDictionary in crescita?

newCap := Length(FItems) * 2; 
if newCap = 0 then 
    newCap := 4; 
Rehash(newCap); 

Questo comporta bene con un numero medio di elementi, ma se si arriva al limite superiore è molto sfortunato, perché potrebbe gettare un EOutOfMemory eccezione anche se è disponibile quasi la metà della memoria.

C'è un modo per influenzare questo comportamento? In che modo le altre classi di raccolta si occupano di questo scenario?

+1

Penso che l'ipotesi di base sia che non si consumi la metà delle risorse disponibili in una singola istanza "TDictionary". Non è progettato per tale utilizzo. –

+0

Quindi questo sarebbe un "no, non è possibile"? – jpfollenius

+3

Una volta che hai consumato metà della memoria, come fai a ridistribuire. Supponiamo di voler aggiungere un altro 10%. Devi assegnare un nuovo blocco, il 10% più grande di quello esistente. Quindi copia dal vecchio al nuovo. Quindi rilasciare vecchio. Non funzionerà. Mi sembra strano che un singolo contenitore possa consumare più della metà delle tue risorse. –

risposta

9

È necessario capire come funziona un dizionario. Un dizionario contiene un elenco di "bucket hash" in cui vengono posizionati gli elementi che inserisci. Questo è un numero finito, quindi una volta che lo hai riempito devi allocare più secchi, non c'è modo di aggirarlo. Poiché l'assegnazione degli oggetti ai bucket si basa sul risultato di una funzione hash, non è possibile semplicemente aggiungere i bucket alla fine dell'array e inserire elementi, è necessario riassegnare l'intero elenco di blocchi, ripeti tutto e mettilo nei (nuovi) secchi corrispondenti.

Dato questo comportamento, l'unico modo per rendere il dizionario non riassegnare una volta pieno è assicurarsi che non si riempia mai. Se conosci il numero di elementi che inserirai nel dizionario, passalo come parametro al costruttore e sarai fatto, non più riallocazioni del dizionario.

Se non riesci a farlo (non sai il numero di elementi che avrai nel dizionario) dovrai riconsiderare ciò che ti ha fatto scegliere lo TDictionary in primo luogo e selezionare una struttura dati che offre un compromesso migliore per il tuo particolare algoritmo. Ad esempio, è possibile utilizzare gli alberi di ricerca binari, poiché eseguono il bilanciamento ruotando le informazioni nei nodi esistenti, senza necessità di riassegnazioni mai.

+0

+1 Grazie! Quello che pensavo era un modo per cambiare il fattore di crescita, in modo che io possa calcolarlo in un modo che mi permetta di usare la memoria disponibile. Guarderò nell'albero di ricerca binario! – jpfollenius

+0

Cambiare il fattore di crescita non ti comprerà molto, se stai già arrivando al punto in cui non puoi più riassegnare. Ci arriverai più lentamente, perché farai più riallocazioni lungo la strada. E grazie alla frammentazione dello spazio dell'indirizzo potresti arrivare più lentamente E con meno articoli aggiunti. –

Problemi correlati