Слабая ссылка

В программировании слабая ссылка (англ. weak reference) — специфический вид ссылок на динамически создаваемые объекты в системах со сборкой мусора или с подсчётом ссылок. Отличается от строгих ссылок тем, что сборщик мусора не учитывает связь ссылки и объекта в куче при выявлении объектов, подлежащих удалению. Таким образом слабая ссылка позволяет работать с объектом как и строгая ссылка, но при необходимости объект будет удален, даже при наличии слабой ссылки на него. Обычные ссылки в контексте сборки мусора иногда именуют «сильными».

Содержание понятия

[править | править код]

Понятие слабой ссылки существует в системах и языках программирования, где поддерживается сборка мусора — автоматическое удаление из памяти объектов, использование которых прекратилось и более не будет возобновлено. Для определения объектов, подлежащих сборке мусора, используется тот или иной вариант алгоритма определения достижимости — достижимым считается объект, на который в программе существует хотя бы одна ссылка. Когда в программе не осталось ни одной ссылки на объект, то есть использование объекта прекратилось, такой объект может быть удалён в ближайший подходящий момент.

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

Чтобы избежать подобных проблем, язык или среда программирования могут поддерживать так называемые слабые ссылки. Такие ссылки используются так же, как и обычные, но не влияют на сборку мусора, поскольку не учитываются механизмом подсчёта ссылок, и объект, на который существуют такие ссылки, может быть удалён, если только на него не существует обычных ссылок (которые в этом контексте могут именоваться «сильными ссылками»).

Реализация и использование

[править | править код]

В распространённых сейчас языках программирования со сборкой мусора — Java и C#, — слабые ссылки поддерживаются на уровне системных библиотек. В Java для этого служат классы java.lang.ref.WeakReference и java.lang.ref.SoftReference, в C# — класс System.WeakReference.

Порядок использования слабых ссылок принципиально одинаков во всех системах.

  1. Когда требуется сохранить слабую ссылку, создаётся объект-реферер (экземпляр класса WeakReference), которому передаётся обычная («сильная») ссылка на целевой объект. Переданная сильная ссылка тут же освобождается, а в реферере хранится её копия в виде, который не может помешать сборщику мусора удалить соответствующий объект. Сам реферер сохраняется как обычный объект, то есть на него должна быть сохранена обычная, «сильная» ссылка.
  2. Когда требуется воспользоваться слабой ссылкой, у реферера вызывается метод get() (в C# — свойство Target), который создаёт и возвращает сильную ссылку на объект, если он ещё существует, или нулевой указатель null (nil), если объект уже удалён сборщиком мусора.
  3. Если реферер вернул действительную ссылку, она далее используется для доступа к объекту обычным образом. Поскольку get() возвращает именно сильную ссылку, во время её использования объект удалён не будет. По завершении её использования объект, на который ссылается реферер, снова становится доступным для сборки мусора. То есть если полученная из реферера сильная ссылка была удалена, для нового использования объекта необходимо получить из реферера новую ссылку и проверить её на равенство нулевому указателю.
  4. Если реферер вернул нулевой указатель, это означает, что объект к моменту обращения уже был удалён сборщиком мусора. Эту ситуацию код программы должен обработать самостоятельно в соответствии с логикой приложения. Например, массив слабых ссылок может работать как кэш для часто используемых данных, хранящихся на внешних носителях; тогда недоступность объекта по слабой ссылке означает необходимость подгрузить его с диска или из СУБД и обновить, при необходимости, запись в кэше.

Режим использования слабых ссылок определяется задачей. Обычная практика — хранение в коллекциях слабых ссылок на объекты, которые нужны только до тех пор, пока приложение эти объекты использует. Когда объект более не требуется и сильные ссылки на него удаляются, слабые ссылки, сохранённые в коллекции, не препятствуют удалению объекта из памяти, благодаря чему можно обойтись без явного удаления их из коллекции.

Особенность класса SoftReference в Java — сборщик мусора при удалении объекта учитывает частоту обращений к нему через эту ссылку, что может быть полезно для реализации кэширования данных, располагающихся, например, на внешних устройствах — коллекция-кэш автоматически дольше удерживает те объекты, к которым чаще обращаются.

Чтобы слабые ссылки на уже не существующие объекты не засоряли память, системные библиотеки предоставляют механизмы для учёта таких ссылок. Вариантом такого механизма являются очереди ссылок — специальные объекты, которые передаются рефереру при создании. Когда сборщик мусора уничтожает объект, на который ссылается слабая ссылка, он помещает в ранее переданную очередь ссылок ссылку на соответствующий реферер. Таким образом, программе доступен список рефереров, содержащих «мёртвые» ссылки, и она может выполнить их удаление в любой подходящий момент.