Hash-consing consiste nel tenere in memoria solo una copia di un dato oggetto; cioè, se due oggetti sono semanticamente uguali (stesso contenuto), allora dovrebbero essere fisicamente uguali (stessa posizione in memoria). La tecnica viene generalmente implementata mantenendo un set di hash globale e creando nuovi oggetti solo se non sono uguali a un oggetto nel set di hash.Hash-consing in F # e tabelle hash deboli in .net
Un ulteriore requisito è che gli oggetti nella tabella hash debbano essere raccolti se non sono referenziati da nulla tranne la tabella hash; diversamente detto, la tabella hash dovrebbe contenere riferimenti deboli.
Il problema è inoltre complicato dalla necessità di disporre di test costanti di tempo, quindi superficiali, di hashing e di uguaglianza; quindi gli oggetti hanno un identificatore univoco che viene incrementato quando un nuovo oggetto viene aggiunto alla tabella.
Ho un'implementazione funzionante che utilizza System.Collections.Generic.Dictionary<key, node>
dove key
è una tupla che fornisce un breve riepilogo del nodo (adatto per l'hashing e il test di uguaglianza predefiniti) e node
è l'oggetto. L'unico problema è che lo Dictionary
mantiene forti riferimenti ai nodi!
Potrei usare un Dictionary
a WeakReference
ma questo non libererebbe le chiavi che puntano a riferimenti ciondolanti.
Alcuni sostengono usando System.Runtime.CompilerServices.ConditionalWeakTable
ma questa classe sembra fare l'opposto: libera il valore quando viene raccolta la chiave, mentre ho bisogno di liberare la chiave quando il valore viene raccolto.
Si potrebbe provare a utilizzare System.Runtime.CompilerServices.ConditionalWeakTable<node, node>
ma avrei bisogno di test di hashing costume e uguaglianza ... e ConditionalWeakTable
non è documentato di utilizzare il metodo virtuale GetHashCode()
, invece di usare la funzione predefinita di hashing.
Quindi la mia domanda: c'è qualche equivalente di Dictionary
che manterrebbe riferimenti deboli ai valori e libererebbe le chiavi quando i riferimenti diventano penzoloni?
È necessario liberare la chiave immediatamente quando viene raccolto il valore? O potresti rilassare il requisito e solo liberare la chiave in un secondo momento? –
Non ho bisogno che vengano liberati immediatamente - è solo che non voglio che si accumulino e consumino inutilmente molta memoria.Ho pensato di eseguire un altro thread per uccidere periodicamente le chiavi con riferimenti ciondolanti, ma questo sembra complicato e soggetto a errori di concorrenza. –
Per quello che vale, ho anche un'implementazione di OCaml usando la tabella hash dal modulo 'Weak', e una implementazione di Java' WeakHashMap'. –