Слабая ссылка
В компьютерном программировании слабая ссылка — это ссылка , которая не защищает объект, на который ссылается , от сбора сборщиком мусора , в отличие от сильной ссылки. Объект, на который ссылаются только слабые ссылки (что означает «каждая цепочка ссылок, которая достигает объекта, включает в себя хотя бы одну слабую ссылку в качестве ссылки»), считается слабо достижимым и может рассматриваться как недостижимый , поэтому его можно собрать в любое время. Некоторые языки со сборкой мусора имеют или поддерживают различные уровни слабых ссылок, например C# , Lua , Java , Lisp , OCaml , Perl , Python. [1] и PHP начиная с версии 7.4. [2]
Использование
[ редактировать ]Слабые ссылки имеют ряд распространенных применений. При использовании с подсчетом ссылок сборки мусора слабые ссылки могут нарушить циклы ссылок , используя слабую ссылку для ссылки в цикле. Когда у вас есть ассоциативный массив (отображение, хеш-карта), ключи которого являются объектами (ссылками на них), например, для хранения вспомогательных данных об объектах, использование слабых ссылок для ключей позволяет избежать сохранения объектов живыми только из-за их использования в качестве ключей. Когда у вас есть объект, в котором зарегистрированы другие объекты, например, в шаблоне наблюдателя (особенно в обработке событий ), если сохраняется сильная ссылка, объекты должны быть явно отменены, в противном случае происходит утечка памяти ( проблема истекшего прослушивателя ), в то время как слабая ссылка устраняет необходимость отмены регистрации. При хранении кешированных данных, которые при необходимости можно воссоздать, слабые ссылки позволяют освободить кеш, эффективно создавая удаляемую память. Этот последний случай (кеш) отличается от других, поскольку предпочтительно, чтобы объекты подвергались сборке мусора только в случае необходимости, и, таким образом, существует необходимость в более тонких различиях внутри слабых ссылок, в данном случае более сильной формы слабой ссылки. Во многих случаях слабые ссылки не нужно использовать напрямую, вместо этого просто используйте слабый массив или другой контейнер , ключи или значения которого являются слабыми ссылками.
Сбор мусора
[ редактировать ]Сбор мусора используется для очистки неиспользуемых объектов и, таким образом, снижает вероятность утечек памяти и повреждения данных. Существует два основных типа сборки мусора: трассировка и подсчет ссылок . Схемы подсчета ссылок записывают количество ссылок на данный объект и собирают объект, когда счетчик ссылок становится равным нулю. Подсчет ссылок не может собирать циклические (или циклические) ссылки, поскольку одновременно можно собирать только один объект. Таким образом, группы взаимно ссылающихся объектов, на которые другие объекты не ссылаются напрямую и которые недоступны, могут стать постоянно резидентными; если приложение постоянно генерирует такие недоступные группы недоступных объектов, это приведет к утечке памяти . Слабые ссылки (ссылки, которые не учитываются при подсчете ссылок) могут использоваться для решения проблемы циклических ссылок, если избежать ссылочных циклов за счет использования слабых ссылок для некоторых ссылок внутри группы.
Очень распространенный случай таких различий между сильными и слабыми ссылками — это древовидные структуры, такие как объектная модель документа (DOM), где ссылки «родитель-потомок» сильны, а ссылки «потомок-родитель» слабы. Например, инфраструктура Apple Cocoa рекомендует такой подход. [3] Действительно, даже когда граф объекта не является деревом, древовидная структура часто может быть обусловлена понятием владения объектом, где отношения владения сильны и образуют дерево, а отношения невладения слабы и не нужны для формирования дерева. – этот подход распространен в C++ (до C++11), используя необработанные указатели в качестве слабых ссылок. Однако у этого подхода есть обратная сторона: он не позволяет определить, когда родительская ветвь была удалена и удалена. Начиная со стандарта C++11 , было добавлено решение с использованием Shared_ptr и Weak_ptr , унаследованных от библиотеки Boost .
Слабые ссылки также используются для минимизации количества ненужных объектов в памяти, позволяя программе указывать, какие объекты имеют второстепенное значение, путем лишь слабых ссылок на них. [ нужна ссылка ]
Вариации
[ редактировать ]Некоторые языки имеют несколько уровней слабой силы ссылок. Например, Java имеет в порядке убывания силы мягкие , слабые и фантомные ссылки, определенные в пакете java.lang.ref . [4] Каждый ссылочный тип имеет связанное с ним понятие достижимости. Сборщик мусора (GC) использует тип достижимости объекта, чтобы определить, когда его освободить. Для GC безопасно освободить объект, который легко доступен, но GC может решить не делать этого, если считает, что JVM может сэкономить память (например, у JVM много неиспользуемой кучи). GC освободит слабодоступный объект, как только GC заметит объект. В отличие от других типов ссылок, фантомная ссылка не может быть использована. С другой стороны, фантомные ссылки предоставляют механизм уведомления программы об освобождении объекта (уведомление реализуется с помощью ReferenceQueues).
В C# слабые ссылки различаются по тому, отслеживают ли они воскрешение объекта или нет. Это различие не наблюдается для сильных ссылок, поскольку объекты не финализируются, если на них есть сильные ссылки. По умолчанию в C# слабая ссылка не отслеживает воскрешение, то есть слабая ссылка не обновляется, если объект воскрешается; они называются короткими слабыми ссылками , а слабые ссылки, отслеживающие воскрешение, называются длинными слабыми ссылками . [5]
Некоторые языки, не использующие сборку мусора, такие как C++ , предоставляют слабую/сильную справочную функциональность как часть поддержки библиотек сборки мусора. Библиотека Boost C++ предоставляет сильные и слабые ссылки. Ошибкой является использование обычных указателей C++ в качестве слабых аналогов интеллектуальных указателей , поскольку такое использование лишает возможности определить, когда счетчик сильных ссылок стал равным 0 и объект был удален. Хуже того, он не позволяет определить, отслеживает ли уже другая сильная ссылка данный простой указатель. Это дает возможность иметь два (или более) интеллектуальных указателя, отслеживающих один и тот же простой указатель (что приводит к повреждению, как только счетчик ссылок одного из этих интеллектуальных указателей достигает 0 и объект удаляется).
Примеры
[ редактировать ]Слабые ссылки могут быть полезны при сохранении списка текущих переменных, на которые ссылаются в приложении. Этот список должен иметь слабые связи с объектами. В противном случае, как только объекты будут добавлены в список, он будет ссылаться на них и будет сохраняться на протяжении всей программы.
Ява
[ редактировать ]Java 1.2 представлена в 1998 году. [6] два типа слабых ссылок, один из которых известен как «мягкая ссылка» (предназначен для поддержки кэшей в памяти, управляемых сборщиком мусора, но на практике работает не очень хорошо на некоторых платформах с динамической кучей, таких как Android). [7] ), а другой просто как «слабая ссылка». Он также добавил родственный экспериментальный механизм, получивший название «фантомные ссылки», в качестве альтернативы опасному и неэффективному механизму Finalize(). [8]
Если создается слабая ссылка, а затем в другом месте кода get()
используется для получения фактического объекта, слабая ссылка недостаточно сильна, чтобы предотвратить сбор мусора, поэтому может быть (если нет сильных ссылок на объект), что get()
внезапно начинает возвращать ноль. [9]
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"
Два
[ редактировать ]weak_table = setmetatable({}, {__mode="v"})
weak_table.item = {}
print(weak_table.item)
collectgarbage()
print(weak_table.item)
Цель-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» и iOS 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;
}
Питон
[ редактировать ]>>> 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'
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ 8.8. слабая ссылка — Слабые ссылки , Стандартная библиотека Python
- ^ «PHP: WeakReference — Руководство» .
- ^ «Практическое управление памятью» . разработчик.apple.com .
- ^ Николас, Итан (4 мая 2006 г.). «Понимание слабых ссылок» . java.net . Архивировано из оригинала 3 марта 2011 г. Проверено 1 октября 2010 г.
- ^ Гольдштейн, Зурбалев и Флатов 2012 , с. 131 .
- ^ «WeakReference (Платформа Java SE 7)» . docs.oracle.com .
- ^ «SoftReference — Разработчики Android» . Developer.android.com .
- ^ «PhantomReference (платформа Java SE 7)» . docs.oracle.com .
- ^ https://web.archive.org/web/20110303225354/http://weblogs.java.net/blog/2006/05/04/understanding-weak-references Примеры Java
- Гольдштейн, Саша; Зурбалев Дима; Флатов, Идо (2012). Производительность Pro .NET: оптимизируйте приложения C# . Апресс. ISBN 978-1-4302-4458-5 .
Внешние ссылки
[ редактировать ]С++
[ редактировать ]- Стандартная библиотека C++11 :
std::weak_ptr
ссылка - Boost 1.59 (библиотека C++) :
boost::weak_ptr
ссылка
Ява
[ редактировать ]- Статья для разработчиков Java: «Справочные объекты и сборка мусора»
- Николас, Итан (4 мая 2006 г.). «Понимание слабых ссылок» . java.net . Архивировано из оригинала 19 августа 2010 года . Проверено 1 октября 2010 г.
{{cite web}}
: CS1 maint: bot: исходный статус URL неизвестен ( ссылка ) - RCache — библиотека Java для кэша на основе слабых/мягких ссылок.
- Теория и практика Java: устранение утечек памяти с помощью слабых ссылок
PHP
[ редактировать ]Питон
[ редактировать ]- слабая ссылка — Слабые ссылки — Документация Python 3
- Фред Л. Дрейк-младший, PEP 205: Слабые ссылки , Предложение по улучшению Python, январь 2001 г.