В компьютерном программировании , слабая ссылка является ссылкой , которая не защищает ссылочный объект из коллекции с помощью сборщика мусора , в отличии от сильной ссылки. Объект ссылается только с помощью слабых ссылок - означает «каждую цепочку ссылок , которая достигает объект содержит , по меньшей мере , один слабая ссылка как ссылку» - считается слабо доступной , и может рассматриваться как недостижимо , и поэтому может быть собрана в любое время. Некоторые языки со сборкой мусора имеют или поддерживают различные уровни слабых ссылок, такие как C # , Java , Lisp ,OCaml , Perl , Python [1] и PHP, начиная с версии 7.4. [2]
Использует
Слабые ссылки имеют ряд распространенных вариантов использования. При использовании сборки мусора с подсчетом ссылок слабые ссылки могут нарушить циклы ссылок , если для ссылки в цикле используется слабая ссылка. Когда у кого-то есть ассоциативный массив (отображение, хеш-карта), ключи которого (ссылки на) объекты, например, для хранения вспомогательных данных об объектах, использование слабых ссылок для ключей позволяет избежать сохранения объектов в живых только из-за их использования в качестве ключа. Когда у кого-то есть объект, в котором зарегистрированы другие объекты, например, в шаблоне наблюдателя (особенно при обработке событий ), если сохраняется сильная ссылка, объекты должны быть явно разрегистрированы, в противном случае происходит утечка памяти ( проблема пропущенного прослушивателя ), в то время как слабая ссылка устраняет необходимость отмены регистрации. При хранении кэшированных данных, которые могут быть воссозданы при необходимости, слабые ссылки позволяют восстановить кэш, эффективно создавая сбрасываемую память. Этот последний случай (кеш) отличается от других, так как предпочтительно, чтобы объекты собирались мусором только в случае необходимости, и, таким образом, существует потребность в более тонких различиях внутри слабых ссылок, здесь более сильная форма слабой ссылки. Во многих случаях нет необходимости напрямую использовать слабые ссылки, вместо этого просто используйте слабый массив или другой контейнер , ключи или значения которого являются слабыми ссылками.
Вывоз мусора
Сборка мусора используется для очистки неиспользуемых объектов и, таким образом, снижения вероятности утечки памяти и повреждения данных. Существует два основных типа сборки мусора: отслеживание и подсчет ссылок . Схемы подсчета ссылок записывают количество ссылок на данный объект и собирают объект, когда счетчик ссылок становится равным нулю. Подсчет ссылок не может собирать циклические (или циклические) ссылки, потому что одновременно может быть собран только один объект. Группы взаимно ссылающихся объектов, на которые не ссылаются напрямую другие объекты и которые недоступны, могут, таким образом, стать постоянно резидентными; если приложение постоянно генерирует такие недостижимые группы недостижимых объектов, это приведет к утечке памяти . Слабые ссылки (ссылки, которые не учитываются при подсчете ссылок) могут использоваться для решения проблемы циклических ссылок, если циклы ссылок избегаются путем использования слабых ссылок для некоторых ссылок внутри группы.
Очень распространенный случай таких сильных и слабых различий ссылок - в древовидных структурах, таких как объектная модель документа (DOM), где ссылки родитель-потомок сильны, а ссылки между потомками - слабыми. Например, фреймворк Apple Cocoa рекомендует этот подход. [3] Действительно, даже когда граф объекта не является деревом, древовидная структура часто может быть навязана понятием владения объектом, где отношения собственности сильны и образуют дерево, а отношения, не связанные с владением, слабы и не нужны для формировать дерево - этот подход распространен в C ++ (до C ++ 11), используя необработанные указатели в качестве слабых ссылок. Однако у этого подхода есть обратная сторона, заключающаяся в том, что он не позволяет определять, когда родительская ветвь была удалена и удалена. Начиная со стандарта C ++ 11 , решение было добавлено с использованием общего ptr и weak ptr , унаследованных от библиотеки Boost .
Слабые ссылки также используются для минимизации количества ненужных объектов в памяти, позволяя программе указывать, какие объекты имеют второстепенное значение, лишь слабо ссылаясь на них.
Вариации
Некоторые языки имеют несколько уровней слабой ссылочной силы. Например, Java имеет в порядке убывания силы мягкие , слабые и фантомные ссылки, определенные в пакете java.lang.ref . [4] С каждым ссылочным типом связано понятие достижимости. Сборщик мусора (GC) использует тип достижимости объекта, чтобы определить, когда освободить объект. Для GC безопасно освободить объект, который является мягко достижимым, но GC может решить не делать этого, если считает, что JVM может сэкономить память (например, JVM имеет много неиспользуемого пространства кучи). Сборщик мусора освободит слабодоступный объект, как только сборщик мусора заметит этот объект. В отличие от других типов ссылок, за фантомной ссылкой нельзя следовать. С другой стороны, фантомные ссылки предоставляют механизм для уведомления программы, когда объект был освобожден (уведомление реализовано с помощью ReferenceQueues).
В C # слабые ссылки различаются по тому, отслеживают ли они воскрешение объекта или нет. Это различие не происходит для строгих ссылок, поскольку объекты не завершаются, если на них есть какие-либо сильные ссылки. По умолчанию в C # слабая ссылка не отслеживает воскрешение, то есть слабая ссылка не обновляется при воскрешении объекта; они называются короткими слабыми ссылками , а слабые ссылки, которые отслеживают воскрешение, называются длинными слабыми ссылками . [5]
Некоторые языки, не использующие сборщик мусора, например C ++ , предоставляют функциональные возможности слабых / сильных ссылок как часть поддержки библиотек сборки мусора. Библиотека Boost C ++ предоставляет сильные и слабые ссылки. Ошибочно использовать обычные указатели C ++ в качестве слабых аналогов интеллектуальных указателей, потому что такое использование лишает возможности определять, когда счетчик сильных ссылок перешел в 0 и объект был удален. Что еще хуже, он не позволяет определить, отслеживает ли уже другая сильная ссылка данный простой указатель. Это вводит возможность наличия двух (или более) интеллектуальных указателей, отслеживающих один и тот же простой указатель (что вызывает повреждение, как только счетчик ссылок одного из этих интеллектуальных указателей достигает 0 и объект удаляется).
Примеры
Слабые ссылки могут быть полезны при ведении списка текущих переменных, на которые ссылается приложение. В этом списке должны быть слабые ссылки на объекты. В противном случае, как только объекты будут добавлены в список, они будут ссылаться на них и будут сохраняться на протяжении всей программы.
Ява
Java 1.2 в 1998 году представила [6] два вида слабых ссылок, один из которых известен как «мягкая ссылка» (предназначенный для использования для поддержки кешей в памяти, управляемых сборщиком мусора, но на некоторых платформах он не очень хорошо работает с динамической кучей, такой как Android [7] ), а другой просто как «слабую ссылку». Он также добавил связанный экспериментальный механизм, получивший название «фантомные ссылки», в качестве альтернативы опасному и неэффективному механизму finalize (). [8]
Если создается слабая ссылка, а затем в другом месте кода get()
используется для получения фактического объекта, слабая ссылка недостаточно сильна, чтобы предотвратить сборку мусора, поэтому может быть (если нет сильных ссылок на объект), что get()
внезапно начинает возвращать null. [9]
import java.lang.ref.WeakReference ;открытый класс ReferenceTest { public static void main ( String [] args ) выбрасывает InterruptedException { WeakReference r = new WeakReference ( "Я здесь" ); StrongReference sr = new StrongReference ( «Я здесь» ); Система . из . println ( "Перед gc: r =" + r . get () + ", static =" + sr . get ()); Система . gc (); Резьба . сон ( 100 ); // Только r.get () становится нулевым. Система . из . println ( "После gc: r =" + r . get () + ", static =" + sr . get ()); } }
Еще одно использование слабых ссылок - это запись кеша . Используя, например, слабую хеш-карту , можно хранить в кэше различные упомянутые объекты через слабую ссылку. При запуске сборщика мусора - когда, например, использование памяти приложением становится достаточно высоким - те кэшированные объекты, на которые больше не ссылаются напрямую другие объекты, удаляются из кеша.
Болтовня
| а s1 s2 |s1 : = 'привет' копия . "это сильная ссылка" s2 : = 'world' copy . «это сильная ссылка» a : = WeakArray с: s1 с: s2 . printOn: Стенограмма . ObjectMemory collectGarbage . printOn: Стенограмма . "оба элемента все еще там" s1 : = ноль . «сильная ссылка уходит» ObjectMemory collectGarbage . printOn: Стенограмма . "первый элемент ушел" s2 : = ноль . «сильная ссылка уходит» ObjectMemory collectGarbage . printOn: Стенограмма . "второй элемент ушел"
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_unreolated NSString * str2 ; }@property ( неатомный , слабый ) NSString * str3 ; @property ( неатомический , unsafe_unretained ) NSString * STR4 ;@конец
Разница между 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
слабые ссылки.
Вала
класс Node { общедоступный слабый узел пред ; // слабая ссылка используется, чтобы избежать циклических ссылок между узлами двусвязного списка public Node next ; }
Python
>>> import weakref >>> import gc >>> class Egg : ... def spam ( self ): ... print ( "Я жив!" ) ... >>> obj = Egg () > >> weak_obj = weakref . ссылка ( объект ) >>> weak_obj () . спам () Я жив! >>> obj = "Что-то еще" >>> gc . collect () 35 >>> weak_obj () . spam () Traceback (последний вызов последним): файл "" , строка 1 , в AttributeError : объект 'NoneType' не имеет атрибута 'spam'
Смотрите также
- Мягкая ссылка
- Фантомная ссылка
- Циркулярная ссылка
- Эфемерон
Рекомендации
- ^ 8.8. weakref - Слабые ссылки , Стандартная библиотека Python
- ^ https://www.php.net/manual/en/class.weakreference.php
- ^ «Практическое управление памятью» . developer.apple.com .
- ^ Николас, Итан (4 мая 2006 г.). «Понимание слабых ссылок» . java.net . Проверено 1 октября 2010 года .
- ^ Гольдштейн, Zurbalev & Flatow 2012 , стр. 131 .
- ^ «WeakReference (Java Platform SE 7)» . docs.oracle.com .
- ^ «SoftReference - разработчики Android» . developer.android.com .
- ^ «PhantomReference (Java Platform 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 Performance: оптимизируйте свои приложения C # . Апресс. ISBN 978-1-4302-4458-5.
Внешние ссылки
C ++
- Стандартная библиотека C ++ 11 : std::weak_ptrсправочник
- Boost 1.59 (библиотека C ++) : boost::weak_ptrсправочник
Ява
- Статья разработчика Java: «Справочные объекты и сборка мусора»
- Николас, Итан (4 мая 2006 г.). «Понимание слабых ссылок» . java.net . Проверено 1 октября 2010 года .
- RCache - библиотека Java для кеширования на основе слабых / мягких ссылок
- Теория и практика Java: устранение утечек памяти с помощью слабых ссылок
PHP
- Слабые ссылки
Python
- https://docs.python.org/3/library/weakref.html
- Фред Л. Дрейк-младший, PEP 205: Слабые ссылки , Предложение по усовершенствованию Python, январь 2001 г.