Wszelkie słabe kolekcje internowania (dla niezmiennych obiektów)

W niektórych sytuacjach związanych z niezmiennymi obiektami możliwe będzie powstanie wielu różnych obiektów, które są semantycznie identyczne. Prostym przykładem może być odczyt wielu wierszy tekstu z pliku na łańcuchy. Z perspektywy programu fakt, że dwie linie mają tę samą sekwencję znaków, byłby „zbiegiem okoliczności”, ale z perspektywy programisty można oczekiwać dużej ilości duplikacji. Jeśli wiele instancji łańcuchów jest identycznych, zmiana odwołań do tych odrębnych instancji na odwołania do pojedynczej instancji pozwoli zaoszczędzić pamięć, a także ułatwi porównania między nimi (jeśli dwa odnośniki łańcuchowe wskazują na ten sam ciąg, nie ma potrzeby wykonywania znaku - porównanie według znaków, aby stwierdzić, że są identyczne).

W niektórych scenariuszach przydatna może być udostępniona przez system usługa internowania łańcuchów. Ma jednak kilka poważnych ograniczeń:

Gdy internowany zostanie ciąg, ta internowana kopia będzie żyć wiecznie, bez względu na to, czy istnieje jakiekolwiek inne odniesienie do niejFunkcja internowania łańcuchów działa tylko z łańcuchami i nie może być używana z żadnymi innymi niezmiennymi typami.

Jeśli istniała prawdaWeakDictionary<ImmutableClassType, ImmutableClassType> (dla każdego elementu klucz i wartość byłyby identyczne), kod mógłby zrobić coś takiego:

if (theDict.TryGetValue(myString, ref internedString))
  myString = internedString;
else
  theDict[myString] = myString;

Niestety nie jestem świadomy żadnego wbudowanegoWeakDictionary<keyType, valType> klasa w .net. Ponadto generowanie słabego odniesienia dla klucza i wartości każdego elementu wydaje się marnotrawstwem, gdy oba odniesienia zawsze wskazują na to samo.

Czytałem o czymśConditionalWeakTable, a to brzmi jak interesująca klasa, ale nie sądzę, żeby mogło być użyteczne tutaj, ponieważ celem jest być w stanie wziąć jedną instancję i znaleźć inną niezależną instancję, która jest semantycznie równoważna.

W sytuacjach, w których wystąpienia klasy będą miały dobrze zdefiniowany czas życia, rozsądne może być użycie konwencjonalnegoDictionary połączyć identyczne instancje. Jednak w wielu przypadkach może być trudno wiedzieć, kiedy takiDictionary powinno zostać porzucone lub elementy w nim wyczyszczone. ZAWeakReferencekolekcja internacjonalizacji oparta na zasadach uniknie takich problemów. Czy coś takiego istnieje lub czy można je łatwo wdrożyć?

Uzupełnienie Jak zauważył svick, aDictionary<WeakReference, WeakReference> byłoby nieco problematyczne, ponieważ nie byłoby praktycznego sposobu zdefiniowaniaIEqualityComparer który miałby żyćWeakReference ZwróćGetHashCode wartość jego celu i martwego nadal zwraca tę wartość. Można zdefiniować strukturę, która zawierałaby całkowitą wartość celu-hashcode (ustawioną w konstruktorze) i której własnąGetHashCode zwróci tę liczbę całkowitą. Niewielką poprawką może być użycieConditionalWeakTable połączyć celWeakReference do finalizowalnego obiektu, który mógłby zostać użyty do kolejkowania elementów tabeli do usunięcia.

Nie jestem pewien, jaka jest właściwa równowaga między próbą skrupulatnego oczyszczenia słownika, a przyjęciem nieco bardziej pasywnego podejścia (np. Wykonaj przemiatanie podczas dodawania elementu, jeśli od ostatniego wobulacji jest co najmniej jeden GC, a liczba jest elementów dodanych od ostatniego przeszukiwania przekracza liczbę elementów, które go przetrwały). Przeglądanie wszystkiego w słowniku nie będzie darmowe, ale ConditionalWeakTable prawdopodobnie też nie będzie darmowe.

PPS Kolejny pomysł, o którym myślałem, ale doszedłem do wniosku, że prawdopodobnie nie byłby tak użyteczny jak podejście o słabym internowaniu, miałby logicznie niezmienny typ o zmiennej wartości „timestamp” i miałby metodę porównywania, która akceptuje argumenty przezref. Jeśli okaże się, że dwie różne instancje są równe, sprawdzone zostaną ich wartości znaczników czasu. Jeśli oba są zerowe, zostaną przypisane kolejne liczby ujemne z licznika globalnego (-1, -2, -3 itd.). Parametr, który miał (lub został przypisany) niższą wartość znacznika czasu, zostałby zastąpiony przez drugi.

Stosując takie podejście, jeśli wiele instancji obiektów było wielokrotnie porównywane ze sobą, wiele odniesień zostałoby zastąpionych odniesieniami do „starszych” instancji. W zależności od wzorców użycia może to spowodować scalenie większości identycznych instancji obiektów bez użycia jakiegokolwiek słownika internowania. Zastosowanie takiego podejścia w przypadku obiektów zagnieżdżonych wymagałoby jednak, aby obiekty „niezmienne” zezwalały na zmutowanie odniesień do obiektów zagnieżdżonych, aby wskazywały na inne rzekomo identyczne obiekty zagnieżdżone. Powinno to być w porządku, jeśli „rzekomo identyczne” obiekty zawsze są, ale mogą powodować dziwaczne niewłaściwe zachowanie, jeśli nie.

questionAnswers(1)

yourAnswerToTheQuestion