Любые слабые коллекции интернирования (для неизменяемых объектов)

В некоторых ситуациях, связанных с неизменяемыми объектами, может возникнуть много различных объектов, которые семантически идентичны. Простым примером может быть чтение многих строк текста из файла в строки. С точки зрения программы, тот факт, что две строки имеют одинаковую последовательность символов, был бы «совпадением», но с точки зрения программиста можно ожидать большого количества дублирования. Если несколько строковых экземпляров идентичны, изменение ссылок на эти отдельные экземпляры в ссылки на один экземпляр сэкономит память, а также облегчит сравнение между ними (если две строковые ссылки указывают на одну и ту же строку, нет необходимости делать символ-сравнение символов, чтобы определить, что они идентичны).

Для некоторых сценариев может быть полезен предоставляемый системой механизм стажировки строк. Однако у него есть несколько серьезных ограничений:

  1. Как только строка интернирована, эта интернированная копия будет жить вечно, независимо от того, существует ли какая-либо другая ссылка на нее.
  2. Средство интернирования строк работает только со строками и не может использоваться с другими неизменяемыми типами.

Если бы существовал истинный WeakDictionary(для каждого элемента ключ и значение были бы идентичны), код мог бы делать что-то вроде:

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

К сожалению, я не знаю ни одного встроенного Класса WeakDictionaryв .net. Кроме того, было бы расточительно создавать слабую ссылку на ключ и значение каждого элемента, когда обе ссылки всегда указывали бы на одно и то же.

Я читал о ConditionalWeakTable, и это звучит как интересный класс,но я не думаю, что его можно было бы использовать здесь, поскольку цель состоит в том, чтобы иметь возможность взять один экземпляр и найти другой независимый экземпляр, который семантически эквивалентен.

Для ситуаций, когда экземпляры класса будут иметь четко определенное время жизни, может быть разумно использовать обычный Словарьдля объединения идентичных экземпляров. Во многих случаях, однако, может быть трудно понять, когда такой словарь должен быть оставлен или элементы в нем очищены. Коллекция интернированных на основе WeakReferenceпозволила бы избежать таких проблем. Существует ли такая вещь или она может быть легко реализована?

Приложение Как отметил Свик, словарь был бы несколько проблематичным, поскольку не было бы практического способа определить IEqualityComparer, который имел бы живой WeakReference, возвращающий GetHashCodeзначение своей цели, и мертвый продолжает возвращать это значение.Можно определить структуру, которая будет содержать целочисленное значение target-hashcode (заданное в конструкторе), и чей собственный GetHashCodeвернет это целое число. Небольшим улучшением может быть использование ConditionalWeakTableдля связывания цели WeakReferenceс завершаемым объектом, который может быть использован для постановки элементов таблицы в очередь для удаления.

Я не уверен, каков правильный баланс между попыткой охотно очистить словарь и использованием несколько более пассивного подхода (например, выполнить зачистку при добавлении элемента, если с момента последней развертки был хотя бы один GC, и количество элементов, добавленных с момента последней развертки, превышает количество элементов, которые пережили его). Пролистывание всего в словаре не будет бесплатным, но ConditionalWeakTable, вероятно, также не будет бесплатным.

ППС Еще одно понятие, о котором я думал, но я подумал, что оно, вероятно, не будет таким же полезным, как подход со слабым интернированием.Логически неизменяемый тип содержит изменяемое значение «метки времени» и метод сравнения, который принимает его аргументы по ref. Если два разных экземпляра окажутся равными, будут изучены их значения меток времени. Если оба ноль, им будут присвоены последовательные отрицательные числа из глобального счетчика (-1, -2, -3 и т.д.). Параметр, который имел (или был назначен) более низкое значение метки времени, затем будет заменен другим.

При таком подходе, если бы многие экземпляры объектов неоднократно сравнивались друг с другом, многие ссылки были бы заменены ссылками на «старые» экземпляры. В зависимости от шаблонов использования это может привести к объединению большинства идентичных экземпляров объектов без использования какого-либо словаря интернирования. Однако применение такого подхода к вложенным объектам потребует, чтобы «неизменяемые» объекты позволяли мутировать ссылки на вложенные объекты, указывая на другие предположительно идентичные вложенные объекты.Это должно быть хорошо, если «предположительно идентичные» объекты всегда есть, но может привести к довольно странному неправильному поведению, если нет.

7
задан svick 28 May 2013 в 12:28
поделиться