Слабая ссылка - Weak reference

В компьютерном программировании , слабая ссылка является ссылкой , которая не защищает ссылочный объект из коллекции с помощью сборщика мусора , в отличии от сильной ссылки. Объект ссылается только с помощью слабых ссылок - означает «каждую цепочку ссылок , которая достигает объект содержит , по меньшей мере , один слабая ссылка как ссылку» - считается слабо доступной , и может рассматриваться как недостижимо , и поэтому может быть собрана в любое время. Некоторые языки со сборкой мусора имеют или поддерживают различные уровни слабых ссылок, такие как C # , Java , Lisp , OCaml , Perl , Python и PHP, начиная с версии 7.4.

Использует

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

Вывоз мусора

Сборка мусора используется для очистки неиспользуемых объектов и, таким образом, снижения вероятности утечки памяти и повреждения данных. Существует два основных типа сборки мусора: отслеживание и подсчет ссылок . Схемы подсчета ссылок записывают количество ссылок на данный объект и собирают объект, когда счетчик ссылок становится равным нулю. Подсчет ссылок не может собирать циклические (или циклические) ссылки, потому что одновременно может быть собран только один объект. Группы взаимно ссылающихся объектов, на которые не ссылаются напрямую другие объекты и которые недоступны, могут, таким образом, стать постоянно резидентными; если приложение постоянно генерирует такие недостижимые группы недостижимых объектов, это приведет к утечке памяти . Слабые ссылки (ссылки, которые не учитываются при подсчете ссылок) могут использоваться для решения проблемы циклических ссылок, если циклы ссылок избегаются путем использования слабых ссылок для некоторых ссылок внутри группы.

Очень распространенный случай таких сильных и слабых различий ссылок - в древовидных структурах, таких как объектная модель документа (DOM), где ссылки родитель-потомок сильны, а ссылки между потомками - слабыми. Например, фреймворк Apple Cocoa рекомендует этот подход. В самом деле, даже когда граф объекта не является деревом, древовидная структура часто может быть навязана понятием владения объектом, где отношения владения сильны и образуют дерево, а отношения, не связанные с владением, являются слабыми и не нужны для формирования дерева. - этот подход распространен в C ++ (до C ++ 11), где необработанные указатели используются в качестве слабых ссылок. Однако у этого подхода есть обратная сторона, заключающаяся в том, что он не позволяет определять, когда родительская ветвь была удалена и удалена. Начиная со стандарта C ++ 11 , решение было добавлено с использованием общего ptr и weak ptr , унаследованных от библиотеки Boost .

Слабые ссылки также используются для минимизации количества ненужных объектов в памяти, позволяя программе указывать, какие объекты имеют второстепенное значение, лишь слабо ссылаясь на них.

Вариации

Некоторые языки имеют несколько уровней слабой ссылочной силы. Например, Java имеет в порядке убывания силы мягкие , слабые и фантомные ссылки, определенные в пакете java.lang.ref . С каждым ссылочным типом связано понятие достижимости. Сборщик мусора (GC) использует тип достижимости объекта, чтобы определить, когда освободить объект. Для GC безопасно освободить объект, который является мягко достижимым, но GC может решить не делать этого, если считает, что JVM может сэкономить память (например, JVM имеет много неиспользуемого пространства кучи). Сборщик мусора освободит слабодоступный объект, как только сборщик мусора заметит этот объект. В отличие от других типов ссылок, за фантомной ссылкой нельзя следовать. С другой стороны, фантомные ссылки предоставляют механизм для уведомления программы, когда объект был освобожден (уведомление реализовано с помощью ReferenceQueues).

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

Некоторые языки, не использующие сборщик мусора, такие как C ++ , предоставляют функциональные возможности слабых / сильных ссылок как часть поддержки библиотек сборки мусора. Библиотека Boost C ++ предоставляет сильные и слабые ссылки. Ошибочно использовать обычные указатели C ++ в качестве слабых аналогов интеллектуальных указателей, потому что такое использование лишает возможности определять, когда счетчик сильных ссылок перешел в 0 и объект был удален. Что еще хуже, это не позволяет определить, отслеживает ли уже другая сильная ссылка данный простой указатель. Это вводит возможность наличия двух (или более) интеллектуальных указателей, отслеживающих один и тот же простой указатель (что вызывает повреждение, как только счетчик ссылок одного из этих интеллектуальных указателей достигает 0 и объект удаляется).

Примеры

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

Джава

Java 1.2 в 1998 году представила два вида слабых ссылок, один из которых известен как «мягкая ссылка» (предназначенный для использования для поддержки кешей в памяти, управляемых сборщиком мусора, но на практике не очень хорошо работает на некоторых платформах с динамической кучей). как Android), а другой - просто как «слабую ссылку». Он также добавил связанный экспериментальный механизм, получивший название «фантомные ссылки», в качестве альтернативы опасному и неэффективному механизму finalize ().

Если создается слабая ссылка, а затем в другом месте кода get()используется для получения фактического объекта, слабая ссылка недостаточно сильна, чтобы предотвратить сборку мусора, поэтому может быть (если нет сильных ссылок на объект), что get()внезапно начинает возвращать null.

import java.lang.ref.WeakReference;

public class ReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        WeakReference r = new WeakReference("I'm here");
        StrongReference sr = new StrongReference("I'm here");
        System.out.println("Before gc: r=" + r.get() + ", static=" + sr.get());
        System.gc();
        Thread.sleep(100);

        // Only r.get() becomes null.
        System.out.println("After gc: r=" + r.get() + ", static=" + sr.get());
    }
}

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

Болтовня

|a s1 s2|

s1 := 'hello' copy.     "that's a strong reference"
s2 := 'world' copy.     "that's a strong reference"
a := WeakArray with:s1 with:s2.
a printOn: Transcript. 
ObjectMemory collectGarbage.
a printOn: Transcript.  "both elements still there"

s1 := nil.              "strong reference goes away" 
ObjectMemory collectGarbage.
a printOn: Transcript.  "first element gone"

s2 := nil.              "strong reference goes away" 
ObjectMemory collectGarbage.
a printOn: Transcript.  "second element gone"

Lua

weak_table = setmetatable({}, {__mode="v"})
weak_table.item = {}
print(weak_table.item)
collectgarbage()
print(weak_table.item)

Objective-C 2.0

В Objective-C 2.0 слабые ссылки будут влиять не только на сборку мусора, но и на автоматический подсчет ссылок. Все переменные и свойства в следующем примере являются слабыми.

@interface WeakRef : NSObject
{
    __weak NSString *str1;
    __unsafe_unretained NSString *str2;
}

@property (nonatomic, weak) NSString *str3;
@property (nonatomic, unsafe_unretained) NSString *str4;

@end

Разница между weak( __weak) и unsafe_unretained( __unsafe_unretained) заключается в том, что когда объект, на который указывает указанная переменная, освобождается, будет ли изменено значение переменной или нет. weakбудут обновлены до, nilа unsafe_unretainedодин останется неизменным, как висячий указатель . Эти weakссылки добавляются к Objective-C , так как Mac OS X 10.7 "Lion" и прошивка 5 , вместе с Xcode 4.1 (4.2 для IOS), и только при использовании ARC. Более старые версии Mac OS X, iOS и GNUstep поддерживают только unsafe_unretainedслабые ссылки.

Вала

class Node {
    public weak Node prev; // a weak reference is used to avoid circular references between nodes of a doubly-linked list
    public Node next;
}

Python

>>> import weakref
>>> import gc
>>> class Egg:
...     def spam(self):
...         print("I'm alive!")
...
>>> obj = Egg()
>>> weak_obj = weakref.ref(obj)
>>> weak_obj().spam()
I'm alive!
>>> obj = "Something else"
>>> gc.collect()
35
>>> weak_obj().spam()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'spam'

Смотрите также

использованная литература

внешние ссылки

C ++

Джава

PHP

Python