Как реализуются слабые ссылки? - PullRequest
17 голосов
/ 23 апреля 2009

Интересно, как слабые ссылки работают внутри, например, в .NET или в Java. Мои две общие идеи:

  1. «Навязчивый» - добавить список слабых ссылок на самый верхний класс (класс объектов). Затем, когда объект уничтожен, все слабые ссылки могут быть повторены и установлены в нуль.
  2. «Ненавязчивый» - чтобы поддерживать хэш-таблицу указателей объектов на списки слабых ссылок. Когда слабая ссылка A создается для объекта B, в хеш-таблице будет изменена или создана запись, ключ которой будет указателем на B.
  3. «Грязный» - хранить специальное хеш-значение с каждым объектом, которое обнуляется при уничтожении объекта. Слабые ссылки копируют это хеш-значение и сравнивают его со значением объекта, чтобы проверить, является ли объект живым. Это, однако, приведет к ошибкам нарушения прав доступа при непосредственном использовании, поэтому, я думаю, потребуется дополнительный объект с таким хэш-значением.

Ни одно из этих решений не кажется ни чистым, ни эффективным. Кто-нибудь знает, как это на самом деле делается?

Ответы [ 5 ]

6 голосов
/ 23 апреля 2009

В .NET, когда создается WeakReference, у GC запрашивается дескриптор / непрозрачный токен, представляющий ссылку. Затем, при необходимости, WeakReference использует этот дескриптор, чтобы спросить GC, является ли этот дескриптор все еще действительным (т.е. оригинальный объект все еще существует) - и, если это так, он может получить фактическую ссылку на объект.

Итак, это построение списка токенов / дескрипторов для адресов объектов (и, вероятно, поддержание этого списка во время дефрагментации и т. Д.)

Я не уверен, что на 100% понимаю три пункта, поэтому не решаюсь предположить, какой из них (если есть) наиболее близок.

5 голосов
/ 23 апреля 2009

Не уверен, что я понял ваш вопрос, но вы можете взглянуть на реализацию класса WeakReference и его ссылки на суперкласс в Java. Это хорошо прокомментировано, и вы можете видеть, что оно имеет поле, специально обработанное GC, и другое поле, используемое непосредственно виртуальной машиной.

3 голосов
/ 03 августа 2013

Похоже, что реализация слабых ссылок - это секрет в отрасли ;-). Например, на данный момент в статье Википедии отсутствуют какие-либо подробности реализации. И посмотрите на ответы выше (включая принятые): «иди посмотри на источник» или «я думаю»; - \.

Из всех ответов проницательный только тот, который ссылается на PEP 205 Python. Как говорится, для любого отдельного объекта может быть не более одной слабой ссылки, если мы будем рассматривать слабую ссылку как саму сущность.

Остальное описывает реализацию языка Squirrel. Таким образом, weakref сам по себе является объектом, когда вы помещаете слабую ссылку на объект в некоторый контейнер, вы фактически помещаете ссылку на объект слабой ссылки. Каждый ref-counttable объект имеет поле для хранения указателя на его слабую ссылку, которая равна NULL до тех пор, пока не будет фактически запрошена слабая ссылка на этот объект. У каждого объекта есть метод для запроса слабого ссылки, который либо возвращает существующее (одноэлементное) слабое отражение из поля, либо создает его и кэширует в поле.

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

И поскольку у объекта есть указатель на его слабую ссылку, тогда объект может обнулять слабую ссылку в собственном деструкторе.

Эта реализация довольно чистая (без волшебных «вызовов в GC» и т. Д.) И имеет O (1) стоимость времени выполнения. Конечно, это довольно жадная память - нужно добавить +1 поле указателя к каждому объекту, хотя обычно для 90 +% объектов это будет NULL. Конечно, VHLL уже имеют большие накладные расходы памяти на объект, и может быть шанс сжать различные «дополнительные» поля. Например, тип объекта обычно представляет собой небольшое перечисление, поэтому может быть возможным объединить тип и некоторую ссылку со слабой ссылкой в ​​одно машинное слово (скажем, хранить объекты со слабой ссылкой в ​​отдельной области и использовать для этого индекс).

2 голосов
/ 23 апреля 2009

Python's PEP 205 имеет достойное объяснение того, как слабые ссылки должны вести себя в Python, и это дает некоторое представление о том, как их можно реализовать. Поскольку слабая ссылка является неизменной, у вас может быть только одна ссылка для каждого объекта, на которую вы раздаете ссылки по мере необходимости. Таким образом, когда объект уничтожен, только одна слабая ссылка должна быть признана недействительной.

0 голосов
/ 09 июня 2012

Я думаю, что нормальный подход состоит в том, чтобы система поддерживала какой-то список слабых ссылок. Когда выполняется сборщик мусора, перед удалением мертвых объектов система выполняет итерацию по списку слабых ссылок и делает недействительной любую ссылку, цель которой не была помечена как живая. В зависимости от системы это может произойти до или после того, как система временно воскресит объекты, которые могут быть немедленно завершены (в случае .net существует два вида WeakReference - один из них эффективно обрабатывается до сканирования системы). для финализаторов, это означает, что он станет недействительным, когда его цель станет подходящей для финализации, и один из которых будет обработан после).

Кстати, если бы я проектировал каркас на основе gc, я бы добавил пару других полезностей: (1) средство объявления хранилища ссылочного типа как содержащего ссылку, в основном интерес к кому-либо еще, и (2) Разнообразие WeakReference, которое может указывать на то, что единственные ссылки на объект находятся в «интересующих кого-то» местах хранения. Хотя WeakReference является полезным типом, акт превращения слабой ссылки в сильную ссылку может помешать системе когда-либо признать, что никто не будет возражать, если ее цель исчезнет.

...