Hash-consing polega na zachowaniu w pamięci tylko jednej kopii danego obiektu; to znaczy, jeśli dwa obiekty są semantycznie równe (ta sama treść), to powinny być fizycznie równe (ta sama lokalizacja w pamięci). Technika jest zwykle realizowana poprzez utrzymywanie globalnego zestawu skrótów i tworzenie nowych obiektów tylko wtedy, gdy nie są one równe obiektowi w zestawie mieszającym.Hash-consing w F # i słabe tablice hash w .net
Dodatkowym wymogiem jest to, że obiekty w tabeli mieszającej powinny być kolekcjonerskie, jeśli nie odwołują się do nich nic poza tablicą skrótów; w przeciwnym razie, tablica asocjacyjna powinna zawierać słabe referencje.
Kwestia ta jest dodatkowo komplikowana potrzebą posiadania stałego czasu, a więc płytkich testów hashowania i równości; w ten sposób obiekty mają unikalny identyfikator, który jest zwiększany po dodaniu nowego obiektu do tabeli.
Mam działającą implementację, która używa System.Collections.Generic.Dictionary<key, node>
gdzie key
jest krotką, co daje płytkie podsumowanie węzła (odpowiednie dla domyślnego testu mieszania i równości) i node
jest obiektem. Jedynym problemem jest to, że Dictionary
utrzymuje silne odniesienia do węzłów!
Mogę użyć Dictionary
do WeakReference
, ale to nie uwolniłoby kluczy wskazujących na wiszące referencje.
Niektórzy adwokat używający System.Runtime.CompilerServices.ConditionalWeakTable
, ale ta klasa wydaje się robić coś odwrotnego: uwalnia wartość, gdy klucz jest zbierany, a ja muszę zwolnić klucz po zebraniu wartości.
Można by spróbować użyć System.Runtime.CompilerServices.ConditionalWeakTable<node, node>
ale musiałbym testy zwyczaj hashowania i równości ... i ConditionalWeakTable
jest udokumentowana nie korzystać z wirtualnego metody GetHashCode()
, zamiast korzystania z funkcji domyślny mieszającego.
W związku z tym moje pytanie: czy istnieje odpowiednik Dictionary
, który utrzymywałby słabe odniesienia do wartości i zwalniał klucze, gdy referencje się zwisały?
Czy musisz zwolnić klucz natychmiast po zebraniu wartości? A może mógłbyś zwolnić to wymaganie i po prostu uwolnić klucz w jakimś późniejszym momencie? –
Nie potrzebuję ich natychmiastowego uwolnienia - po prostu nie chcę, żeby się gromadzili i bezużytecznie zużywają dużo pamięci.Myślałem o uruchomieniu innego wątku, aby okresowo zabijać klucze z wiszącymi referencjami, ale wydaje się to być skomplikowane i podatne na błędy współbieżności. –
Za to, co jest warte, mam również implementację OCaml przy użyciu tablicy mieszającej z modułu 'Weak' oraz implementacji Java usiong' WeakHashMap'. –