В чем отличия softreference и weakreference в android

Обновлено: 16.05.2024

слабые ссылки

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

и затем в другом месте кода Вы можете использовать weakWidget.get() чтобы получить фактическое

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

SoftReferences с другой стороны хороши для кэширования внешних, воссоздаваемых ресурсов ГХ, как правило, задержки очищая их. Это гарантировано, хотя что все SoftReferences будут очищены до OutOfMemoryError, поэтому они теоретически не может вызвать OOME [*].

типичным примером использования является сохранение проанализированной формы содержимого из файл. Вы бы внедрили систему, в которой вы загружаете файл, анализируете его и сохраняете SoftReference к корневому объекту анализируемого представления. В следующий раз вам нужен файл, вы попытаетесь получить его через SoftReference. Если вы можете получить его, вы избавили себя от другой нагрузки / разбора, и если GC очистил его, а ты перезаряди. Таким образом, вы используете бесплатно память для оптимизации производительности, но не рискуйте OOME.

теперь [*]. Сохранение SoftReference не может вызвать OOME само по себе. Если с другой руку вы по ошибке использовать SoftReference для задания каждого предназначена для использования (а именно, вы каким-то образом сохраняете информацию, связанную с объектом сильно ссылается и отбрасывает его, когда ссылочный объект получает очищено), вы можете запустить в OOME в качестве кода, который опрашивает ReferenceQueue и отбрасывает связанные объекты, которые могут не выполняться своевременно мода.

Итак, решение зависит от использования - если вы кэшируете информацию, которая является дорогостоящей для создания, но тем не менее, реконструируемый из других данных, используйте мягкие ссылки - если вы сохраняете ссылку на канонический экземпляр некоторых данных, или вы хотите иметь ссылку на объект без "владения" (таким образом, предотвращение его от GC'D), используйте слабую ссылку.

В Java; порядок от сильнейшего к слабейшему, есть: сильный, мягкий, слабый и Фантом

на ссылка - это обычная ссылка, которая защищает упомянутый объект от сбора GC. т. е. никогда мусор не собирает.

на мягкая ссылка имеет право на сборку сборщиком мусора, но, вероятно, не будет собран, пока его память не понадобится. т. е. мусор собирает перед OutOfMemoryError .

A слабые ссылки - это ссылка, которая не защищает ссылочный объект от коллекции GC. т. е. мусор собирает, когда нет сильных или мягких refs.

на Phantom reference ссылка на объект phantomly ссылается после того, как он был завершен, но до того, как его выделенная память была восстановлена.

аналогия: предположим, что JVM-это королевство, объект-король королевства, и GC является нападающим Королевства, который пытается убить короля (объект).

  • когда король сильный, GC не может убить его.
  • когда король софт, GC атакует его, но король правит королевством с защитой до тех пор, пока ресурс не будет доступен.
  • когда король слабый, GC атакует его, но правит королевством без защиты.
  • когда король Фантом, GC уже убил его, но король доступен через его душу.

принцип: weak reference связано со сбором мусора. Как правило, объект, имеющий один или несколько reference не будет иметь право на вывоз мусора.
Вышеуказанный принцип не применим, когда он weak reference . Если объект имеет только слабую ссылку на другие объекты, то он готов к мусору коллекция.

давайте посмотрим на примере: у нас есть Map с объектами, где ключ является ссылкой на объект.

теперь, во время выполнения программы мы сделали emp = null . The Map удержание ключа не имеет смысла здесь, как это null . В приведенной выше ситуации объект не является собранным мусором.

WeakHashMap

WeakHashMap где записи ( key-to-value mappings ) будет удален, когда его нет дольше можно получить их из Map .

позвольте мне показать приведенный выше пример с WeakHashMap

выход: 20 calls to System.gc() в результате aMap size of: 0.

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

Мягкие Ссылки.

Soft Reference немного сильнее, что слабая ссылка. Мягкая ссылка позволяет собирать мусор, но просит сборщика мусора очистить его, только если нет другого варианта.

сборщик мусора не агрессивно собирает мягко достижимые объекты, как это происходит со слабо достижимыми - вместо этого он только собирает мягко достижимые объекты, если им действительно "нужна" память. Мягкие ссылки-это способ сказать сборщику мусора: "пока память не слишком плотная, я хотел бы сохранить этот объект. Но если память станет очень тугой, давай, собери ее, и я разберусь с этим."Сборщик мусора должен очистить все мягкие ссылки, прежде чем он сможет бросить OutOfMemoryError .

единственное реальное различие между мягкой ссылкой и слабой ссылкой заключается в том, что сборщик мусора uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.

SoftReference предназначен для схрона. Когда обнаружено, что a WeakReference ссылается на недостижимый в противном случае объект, затем он будет немедленно очищен. SoftReference можно оставить как есть. Как правило, существует некоторый алгоритм, связанный с объемом свободной памяти и временем последнего использования, чтобы определить, следует ли его очистить. Текущий алгоритм Sun должен очистить ссылку, если она не была использована за столько секунд, сколько есть мегабайт свободной памяти в куче Java (настраиваемый, сервер HotSpot проверяет максимально возможную кучу, установленную -Xmx ). SoftReference s будет очищен до OutOfMemoryError выбрасывается, если иное не достижимо.

Единственная Реальная Разница

Per док, свободные WeakReferences должны очищается запущенным GC.

Per док, свободные SoftReferences должны очистится до того, как будет брошен ум.

это единственная реальная разница. Все остальное не входит в контракт. (Я предполагаю, что последние документы являются договорными.)

SoftReferences полезны. чувствительные к памяти кэши используйте SoftReferences, а не WeakReferences.

Единственное правильный использование WeakReference заключается в наблюдении за запуском GC. Вы делаете это, создавая новый WeakReference, объект которого сразу выходит за рамки, а затем попробуйте получить null из weak_ref.get() . Когда это null , вы узнаете, что между этой продолжительностью GC побежал.

как неправильно использование WeakReference, список бесконечен:

паршивый хак, чтобы связать данные с объектом существующего класса, пока он создает утечку памяти (OutOfMemoryError), когда ваш GC решает сделать перерыв после создания ваших weakreferences. Кроме того, это более чем уродливо: лучший подход-использовать кортежи.

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

шесть типов состояний достижимости объектов в Java -

  1. сильныйly достижимые объекты-GC не будет собрать (освободить память, занятую) такого рода объекты. Это достижимый через корневой узел или другой сильно достижимый объект (т. е. через локальные переменные, переменные класса, переменные экземпляра и т. д.)
  2. софтly достижимые объекты-GC попытка для собирайте объекты такого типа в зависимости от конкуренции памяти. Они доступны из корня через один или несколько мягкие ссылочные объекты
  3. слабыйly достижимые объекты-GC должны сбор такого рода объекты. Эти доступны от корня через один или несколько слабые ссылки на объекты
  4. воскрешение-в состоянии objects-GC уже находится в процессе сбора этих объектов. Но!--4-->они могут пойти назад в одно из состояний-сильное/мягкое / слабое путем выполнения некоторого финализатора
  5. Фантомly достижимый объект-GC уже находится в процессе сбора этих объектов и определил, что не может быть воскрешен любым финализатором (если он объявляет сам метод finalize (), то его финализатор будет запущен). Они доступны из корня через один или несколько Фантом ссылка объекты
  6. недоступен объект-объект не является ни сильно, мягко, слабо, ни Фантом достижимым, и не воскрешается. Эти объекты готовы к рекультивации

Слабые Ссылки

когда есть одна или несколько ссылок на объект, это не будет мусор, собранный в Java. Но это правило зависит от типа ссылки. Если объект имеет только слабую ссылку, связанную с другими объектами, то он является допустимым кандидатом на сборку мусора.

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


ключ-объект TextView, а значение-идентификатор. Теперь во время выполнения программы мы удалили объект TextView, скажем textView1. Нам не требуется этот объект представления, поэтому мы сделали его null. Теперь, что произойдет с парой ключ-значение (textView1, iD1), хранящейся в HashMap. Эта пара на данный момент не имеет смысла и не требуется поскольку сам textview имеет значение null.

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

Мягкая Ссылка

мягкая ссылка немного сильнее, чем слабая ссылка. Мягкая ссылка позволяет мусор сбор, но просит сборщик мусора очистить его, только если нет другого варианта. То есть он имеет право на сборку мусора, но сборщик мусора может удалить его на основе хруста памяти. Если у него осталось мало памяти и он в состоянии восстановить память, то он будет собирать мягкие ссылки.

этой статьи может быть очень полезно понять сильные, мягкие, слабые и фантомные ссылки.

чтобы дать вам резюме,

Если у вас есть только слабые ссылки к объекту (без сильных ссылок), тогда объект будет возвращен GC в самом следующем цикле GC.

Если у вас есть только мягкие ссылки к объекту (без сильных ссылок), тогда объект будет исправлен GC только тогда, когда JVM не хватает памяти.

таким образом, вы можете сказать, что сильные ссылки имеют высшая власть (никогда не может быть собран GC)

мягкие ссылки мощный чем слабые ссылки (поскольку они могут избежать цикла GC, пока JVM не закончится память)

слабые ссылки даже менее мощный чем мягкие ссылки (поскольку они не могут excape любой цикл GC и будут исправлены, если объект не имеет других сильных ссылка.)

Ресторан Аналогии

  • официант-GC
  • Вы - объект в куче
  • ресторанная зона/пространство - пространство "кучи"
  • новый клиент-новый объект, который хочет стол в ресторане

теперь, если вы сильная клиентов (аналогично сильная ссылка), то даже если новый клиент приходит в ресторан или что так когда-либо happnes, вы никогда не оставляйте таблица (область памяти в куче). Официант не имеет права говорить вам (или даже просить вас) покинуть ресторан.

Если вы мягкая поддержки (аналогично мягкой ссылке), то, если новый клиент приходит в ресторан, официант не попросит вас покинуть стол, если нет другого пустого стола, чтобы разместить нового клиента. (Другими словами, официант попросит вас выйти из-за стола, только если появится новый клиент, а другого стола нет оставлено для этого нового клиента)

Если вы слаб клиентов (аналогично слабой ссылке), то официант, по своей воле, может (в любой момент времени) попросить вас покинуть ресторан :P

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

WeakReference: объекты, на которые только слабо ссылаются, собираются в каждом цикле GC (minor или full).

SoftReference: когда собираются объекты, на которые только мягко ссылаются, зависит от:

- XX: SoftRefLRUPolicyMSPerMB=N флаг (значение по умолчанию 1000, ака 1 секунда)

объем свободной памяти в куче.

  • куча имеет 10 МБ свободного места (после полного GC);
  • - XX: SoftRefLRUPolicyMSPerMB=1000

тогда объект, на который ссылается только SoftReference, будет собран, если в последний раз, когда он был доступен, больше 10 секунд.

image

После этой встречи мы начинаем более бережно относится к используемой памяти, экономить ее. Начиная с версии 1.2 в Java появился пакет java.lang.ref.* с классами SoftReference, WeakReference, PhantomReference. Далее я расскажу вам о том, как помогут эти классы в борьбе с OutOfMemoryError. И что более интересно, приведу реальные примеры их использования. Начнем.

Общее Описание

  1. SoftReference — если GC видит что объект доступен только через цепочку soft-ссылок, то он удалит его из памяти. Потом. Наверно.
  2. WeakReference — если GC видит что объект доступен только через цепочку weak-ссылок, то он удалит его из памяти.
  3. PhantomReference — если GC видит что объект доступен только через цепочку phantom-ссылок, то он его удалит из памяти. После нескольких запусков GC.
  • builder — strong-ссылка
  • softBuilder — soft-ссылка (формально это strong-ссылка на soft-ссылку, но для простоты я буду писать soft-ссылка)

Детали SoftReference

Особенности GC

Так всё же, как ведет себя GC когда видит что объект доступен только по цепочке soft-ссылок? Давайте рассмотрим работу GC более детально:
И так, GC начал свою работу и проходит по всем объектам в куче. В случае, если объект в куче это Reference, то GC помещает этот объект в специальную очередь в которой лежат все Reference объекты. После прохождения по всем объектам GC берет очередь Reference объектов и по каждому из них решает удалять его из памяти или нет. Как именно принимается решение об удалении объекта — зависит от JVM. Но общий контракт звучит следующим образом: GC гарантировано удалит с кучи все объекты, доступные только по soft-ссылке, перед тем как бросит OutOfMemoryError.
SoftReference это наш механизм кэширования объектов в памяти, но в критической ситуации, когда закончится доступная память, GC удалит не использующиеся объекты из памяти и тем самым попробует спасти JVM от завершения работы. Это ли не чудно?
Вот как Hotspot принимает решение об удалении SoftReference: если посмотреть на реализацию SoftReference, то видно, что в классе есть 2 переменные — private static long clock и private long timestamp. Каждый раз при запуске GC, он сетит текущее время в переменную clock. Каждый раз при создании SoftReference, в timestamp записывается текущее значение clock. timestamp обновляется каждый раз при вызове метода get() (каждый раз, когда мы создаем strong-ссылку на объект). Это позволяет вычислить, сколько времени существует soft-ссылка после последнего обращения к ней. Обозначим этот интервал буквой I. Буквой F обозначим количество свободного места в куче в MB(мегабайтах). Константой MSPerMB обозначим количество миллисекунд, сколько будет существовать soft-ссылка для каждого свободного мегабайта в куче.
Дальше все просто, если I <= F * MSPerMB, то не удаляем объект. Если больше то удаляем.
Для изменения MSPerMB используем ключ -XX:SoftRefLRUPolicyMSPerMB. Дефалтовое значение — 1000 ms, а это означает что soft-ссылка будет существовать (после того как strong-ссылка была удалена) 1 секунду за каждый мегабайт свободной памяти в куче. Главное не забыть что это все примерные расчеты, так как фактически soft-ссылка удалится только после запуска GC.
Обратите внимание на то, что для удаления объекта, I должно быть строго больше чем F * MSPerMB. Из этого следует что созданная SoftReference проживет минимум 1 запуск GC. (*если не понятно почему, то это останется вам домашним заданием).
В случае VM от IBM, привязка срока жизни soft-ссылки идет не к времени, а к количеству переживших запусков GC.

Применение

Главная плюшка SoftReference в том что JVM сама следит за тем нужно удалять из памяти объект или нет. И если осталось мало памяти, то объект будет удален. Это именно то, что нам нужно при кэшировании. Кэширование с использованием SoftReference может пригодится в системах чувствительных к объему доступной памяти. Например, обработка изображений. Первый пример применения будет немного выдуманным, зато показательным:
Наша система занимается обработкой изображений. Допустим, у нас есть громадное изображение, которое находиться где-то в файловой системе и это изображение всегда статично. Иногда пользователь хочет соединить это изображение с другим изображением. Вот наша первая реализация такой конкатенации:


Недостатков в таком подходе много, но один из них это то что мы должны каждый раз загружать с файловой системы изображение. А это не самая быстрая процедура. Давайте тогда будем кешировать загруженное изображение. Вот вторая версия:


Этот вариант уже лучше, но проблема все ровно есть. Изображение большое и забирает много памяти. Наше приложение работает со многими изображениями и при очередной попытке пользователя обработать изображение, легко может свалиться OutOfMemoryError. И что с этим можно сделать? Получается, что нам нужно выбирать, либо быстродействие либо стабильность. Но мы то знаем о существовании SoftReference. Это поможет нам продолжать использовать кеширование, но при этом в критических ситуациях выгружать их из кэша для освобождения памяти. Да еще и при этом нам не нужно беспокоиться о детектировании критической ситуации. Вот так будет выглядеть наша третья реализация:


Эта версия не идеальна, но она показывает как просто мы можем контролировать размер занимаемый кэшем, а точнее возложить контроль на виртуальную машину. Опасность данной реализации заключается в следующем. В строчке №1 мы делаем проверку на null, фактически мы хотим проверить, удалил GC данные с памяти или нет. Допустим, что не удалил. Но перед выполнением строки №2 может начать работу GC и удалить данные. В таком случае результатом выполнения строчки №2 будет defaultImage = null. Для безопасной проверки существования объекта в памяти, нам нужно создать strong-ссылку, defaultImage = defaultImageRef.get(); Вот как будет выглядеть финальная реализация:


Пойдем дальше. java.lang.Class тоже использует SoftReference для кэширования. Он кэширует данные о конструкторах, методах и полях класса. Интересно посмотреть, что именно они кешируют. После того как решено использовать SoftReference для кеширования, нужно решить что именно кешировать. Допустим нам нужно кешировать List. Мы можем использовать как List<SoftReference> так и SoftReference<List>. Второй вариант более приемлемый. Нужно помнить, что GC применяет специфическую логику при обработке Reference объектов, да и освобождение памяти будет происходить быстрее если у нас будет 1 SoftReference а не их список. Это мы и видим в реализации Class — разработчики создали soft-ссылку на массив конструкторов, полей и методов. Если говорить про производительность, то стоить отметить что часто, ошибочно, люди используют WeakReference для построения кэша там где стоит использовать SoftReference. Это приводит к низкой производительности кэша. На практике weak-ссылки быстро будут удалены из памяти, как только исчезнут strong-ссылки на объект. И когда нам реально понадобиться вытянуть объект с кэша, мы увидим что его там уже нет.
Ну и еще один пример использования кэша на основе SoftReference. В Google Guava есть класс MapMaker. Он поможет нам построить ConcurrentMap в которой будут следующая особенность — ключи и значения в Map могут заворачиваться в WeakReference или SoftReference. Допустим в нашем приложении есть данные, которые может запросить пользователь и эти данные достаются с базы данных очень сложным запросом. Например, это будет список покупок пользователя за прошлый год. Мы можем создать кэш в котором значения (список покупок) будут храниться с помощью soft-ссылок. А если в кэше не будет значения то нужно вытянуть его с БД. Ключом будет ID пользователя. Вот как может выглядеть реализация:

WeakReference
Особенности GC

Теперь рассмотрим более детально, что же собой представляет WeakReference. Когда GC определяет, что объект доступен только через weak-ссылки, то этот объект «сразу» удаляется с памяти. Тут стоить вспомнить про ReferenceQueue и проследить за порядком удаления объекта с памяти. Напомню что для WeakReference и SoftReference алгоритм попадания в ReferenceQueue одинаковый. Итак, запустился GC и определил что объект доступен только через weak-ссылки. Этот объект был создан так:

Сначала GC очистит weak-ссылку, то есть weakRef.get() – будет возвращать null. Потом weakRef будет добавлен в queue и соответственно queue.poll() вернет ссылку на weakRef. Вот и все что хотелось написать про особенности работы GC с WeakReference. Теперь посмотрим, как это можно использовать.

Применение
  • WeakHashMap не предназначена для использования в качестве кэша. WeakReference создается для ключа а не для значения. И данные будут удалены только после того как в программе не останется strong-ссылок на ключ а не на значение. В большинстве случаев это не то чего вы хотите достичь кэшированием.
  • Данные с WeakHashMap будут удалены не сразу после того как GC обнаружит что ключ доступен только через weak-ссылки. Фактически очистка произойдет при следующем обращении к WeakHashMap.
  • В первую очередь WeakHashMap предназначен для использования с ключами, у которых метод equals проверяет идентичность объектов (использует оператор ==). Как только доступ к ключу потерян, его уже нельзя создать заново.

Ну а вот чтение:

UserInfo будет находиться в WeakHashMap до тех пор пока GC не заметит, что на mainDocument остались только weak-ссылки.
Другой пример использования WeakHashMap. Многие знают про метод String.intern(). Так вот с помощью WeakReference можно создать нечто подобное. (Давайте не будет обсуждать, в рамках этой статьи, целесообразность этого решения, и примем факт, что у этого решения есть некоторые преимущества по сравнению с intern()). Итак, у нас есть ооочень много строк. Мы знаем что строки повторяются. Для сохранения памяти мы хотим использовать повторно уже существующие объекты, а не создавать новые объекты для одинаковых строк. Вот как в этом нам поможет WeakHashMap:

И на последок добавлю, что WeakReference используется во многих классах – Thread, ThreadLocal, ObjectOutpuStream, Proxy, LogManager. Вы можете посмотреть на их реализацию для того чтоб понять в каких случаях вам может помочь WeakReference.

PhantomReference
Особенности GC

Особенностей у этого типа ссылок две. Первая это то, что метод get() всегда возвращает null. Именно из-за этого PhantomReference имеет смысл использовать только вместе с ReferenceQueue. Вторая особенность – в отличие от SoftReference и WeakReference, GC добавит phantom-ссылку в ReferenceQueue послетого как выполниться метод finalize(). Тоесть фактически, в отличии от SoftReference и WeakReference, объект еще есть в памяти.

Типы ссылок в Java

Любой объект, к которому прилагается Сильная ссылка, не имеет права на сбор мусора. Например:

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

WeakReference и SoftReference в Java

Для начала давайте рассмотрим разницу между WeakReference и SoftReference в Java.

Если вкратце, то сборщик мусора освободит память объекта, если на него указывают только слабые ссылки. Когда на объект указывают ссылки SoftReferences, то освобождение памяти происходит, когда JVM сильно нуждается в памяти.

Это дает определенное преимущество SoftReference перед Strong ссылкой в определенных случаях. Например, SoftReference используют для реализации кэша приложений, поэтому JVM первым делом удалит объекты, на которые указывают только SoftReferences.

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

Пример WeakReference в Java:

WeakReference <Student> weakStudent = new WeakReference <Student> ( student ) ; // теперь объект Student может быть собран сборщиком мусора

Пример SoftReference в Java:

SoftReference <Student> softStudent = new SoftReference <Student> ( student ) // теперь объект Student может быть собран сборщиком мусора // но это случится только в случае сильной необходимости JVM в памяти

Ссылка PhantomReference в Java

Экземпляр PhantomReference создается точно также, как и на примерах WeakReference и SoftReference, но используется он довольно редко.

PhantomReference может быть собрана сборщиком мусора, если на объект нет сильных (Strong), слабых ссылок (WeakReference) или мягких (SoftReference).

PhantomReference может использоваться в ситуациях, когда использование finalize() не имеет смысла. Этот ссылочный тип отличается от других типов, поскольку он не предназначен для доступа к объекту. Он является сигналом о том, что объект уже финализирован и сборщик мусора готов вернуть свою память.

Здесь PhantomReference является гибким и безопасным выбором. Ссылка на старое изображение будет передана в ReferenceQueue после уничтожения старого объекта изображения. Получив эту ссылку, мы можем загрузить новое изображение в память.

Слабые ссылки

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

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

.

Мягкие ссылки

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

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

И Питер Кесслер добавил в комментарии:

Sun JRE действительно обрабатывает SoftReferences иначе, чем WeakReferences. Мы пытаемся удержать объект, на который ссылается SoftReference, если нет давления на доступную память. Одна деталь: политики для JRE «-client» и «-server» различаются: JRE -client пытается уменьшить ваш размер, предпочитая очищать SoftReferences, а не расширять кучу, тогда как JRE -server пытается сохранить ваш высокая производительность, предпочитая расширять кучу (если возможно), а не очищать SoftReferences. Один размер не подходит для всех.

В Java ; По порядку от сильнейшего к самому слабому: Сильный, Мягкий, Слабый и Призрачный.

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

Мягкая ссылка может быть собрана сборщиком мусора, но, вероятно, не будет собрана, пока ее память не понадобится. т.е. мусор собирается до OutOfMemoryError .

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

Фантомная ссылка - это ссылка на объект, на который фантомно ссылаются после того, как он был завершен, но до того, как его выделенная память будет освобождена.

Аналогия: Предположим, что JVM - это королевство, Object - король королевства, а GC - атакующий королевство, который пытается убить короля (объект).

  • Когда Кинг Сильный , GC не может его убить.
  • Когда Король Мягкий , GC атакует его, но Король правит королевством с защитой до тех пор, пока не будут доступны ресурсы.
  • Когда король слаб , GC атакует его, но правит королевством без защиты.
  • Когда королем является Фантом , GC уже убил его, но король доступен через его душу.
Мягкая ссылка . until memory is available не имеет смысла. Вы имеете в виду is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use ? Да, сборщик мусора не будет собирать ссылку, пока не освободится память. Мне нравятся простые объяснения, без лишнего бла-бла-бла +1 от меня!

Принцип: weak reference связан со сборкой мусора. Обычно объект с одним или несколькими reference не подлежит сборке мусора.
Вышеупомянутый принцип неприменим, если это weak reference . Если объект имеет только слабую ссылку с другими объектами, он готов к сборке мусора.

Давайте посмотрим на приведенный ниже пример: у нас есть Map с объектами, где ключ ссылается на объект.

Теперь во время выполнения программы мы сделали emp = null . Map , удерживающий ключ, здесь не имеет смысла, так как он есть null . В приведенной выше ситуации сборщиком мусора не выполняется.

WeakHashMap

WeakHashMap - это тот, где записи ( key-to-value mappings ) будут удалены, когда их больше невозможно будет получить из Map .

Позвольте мне показать тот же пример с WeakHashMap .

Вывод: взял 20 calls to System.gc() , чтобы получить aMap size из: 0.

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

Мягкие ссылки .

Soft Reference немного сильнее этой слабой ссылки. Мягкая ссылка разрешает сборку мусора, но просит сборщик мусора очистить ее, только если нет другого варианта.

Сборщик мусора не собирает агрессивно легко достижимые объекты, как это происходит со слабодоступными - вместо этого он собирает мягко доступные объекты только в том случае, если ему действительно «нужна» память. Мягкие ссылки - это способ сказать сборщику мусора: «Пока память не слишком тесна, я хотел бы сохранить этот объект. с этим. " Сборщик мусора должен очистить все мягкие ссылки, прежде чем он сможет выбросить OutOfMemoryError .

Вы можете получить NullPointerException в aMap.get().put(. ) . Ваш первый пример HashMap выглядит неправильно. Когда вы выполняете "aMap.put (emp, val);" как "emp", так и "val" - сильные ссылки. Внутри создается новая переменная для хранения «emp» и «val», поэтому, когда вы выполняете «emp = null;» вы просто обнуляете переменную "emp", но не внутреннюю переменную для хэш-карты (которая все еще содержит исходный объект Employee). Следовательно, хеш-карта по-прежнему будет содержать сильную ссылку на emp, независимо от того, что вы делаете с внешней переменной emp. Выполнено 0 вызовов System.gc (), в результате чего размер weakHashMap равен: 0 - это результат вашей второй программы? Другой пример работы WeakHashMap с примером приложения, показывающим, как записи удаляются только после выполнения сборки мусора, см. В мой ответ на вопрос, постоянно растет WeakHashMap или устраняет мусорные ключи? .

SoftReference предназначен для кешей. Когда обнаруживается, что WeakReference ссылается на другой недостижимый объект, он немедленно очищается. SoftReference можно оставить как есть. Обычно существует некоторый алгоритм, связанный с объемом свободной памяти и временем последнего использования, чтобы определить, следует ли ее очистить. Текущий алгоритм Sun состоит в том, чтобы очистить ссылку, если она не использовалась столько секунд, сколько мегабайт свободной памяти в куче Java (настраивается, сервер HotSpot проверяет максимально возможную кучу, установленную -Xmx ). SoftReference будут сброшены до того, как будет брошен OutOfMemoryError , если не будет достигнуто иное.

@YaroslavMytkalyk, Откровенно говоря, если Android хочет переписать поведение класса, он должен использовать собственное пространство имен, а не java.lang . Такое злоупотребление синонимами никому не приносит никакой пользы.

Эта статья может быть очень полезной для понимания сильных , мягкие, слабые и фантомные ссылки.

Чтобы дать вам резюме,

Если у вас есть только слабые ссылки на объект (без сильных ссылок), то объект будет возвращен сборщиком мусора в следующем цикле сборщика мусора.

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

Таким образом, вы можете сказать, что сильные ссылки имеют абсолютную силу (никогда не могут быть собраны GC)

Мягкие ссылки мощнее , чем слабые (поскольку они могут избежать цикла сборки мусора, пока JVM не исчерпает память)

Слабые ссылки даже менее эффективны , чем мягкие ссылки (поскольку они не могут исключать цикл сборки мусора и будут восстановлены, если у объекта нет другой сильной ссылки).

Аналогия с рестораном

  • Официант - GC
  • Вы - объект в куче
  • Площадь / пространство ресторана - Пространство в куче
  • Новый клиент - новый объект, которому нужен столик в ресторане

Теперь, если вы являетесь сильным клиентом (аналогично сильному отзыву), то даже если в ресторан зайдет новый клиент или что-то подобное случится, вы никогда не покинете свой стол (область памяти в куче) . Официант не имеет права сказать вам (или даже попросить) покинуть ресторан.

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

Если вы слабый покупатель (аналог слабого отзыва), то официант по своему желанию может (в любой момент) попросить вас покинуть ресторан: P

Единственная реальная разница

Согласно документу свободные ссылки WeakReferences должны быть удалены путем выполнения GC.

Согласно документу свободные ссылки SoftReferences должны быть очищены перед тем, как OOM брошен.

Это единственная реальная разница. Все остальное не является частью контракта. (Я предполагаю, что последние документы являются договорными.)

Полезны SoftReferences. В кэше, зависящем от памяти, используются SoftReferences, а не WeakReferences.

Правильный weak_ref.get() null

Что касается неправильного использования WeakReference, список бесконечен:

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

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

А как насчет кеша, в котором тип ключа equals() является просто идентификатором объекта? Мягкие ссылки кажутся здесь пустой тратой, потому что, как только ключевой объект становится недоступным, никто больше никогда не будет искать это сопоставление. Я не согласен. Используйте WeakReference, если вы никоим образом не хотите влиять на GC (вы можете сохранить ссылку на объект, а затем проверить позже, существует ли она еще, без каких-либо предпочтений). Используйте SoftReference, если вы хотите повлиять на сборщик мусора, чтобы он попытался сохранить объект (т. Е. Когда вы бы предпочли, чтобы сборщик мусора сохранил его). Хороший пример использования WeakReference - в AsyncTask Android - для сохранения экземпляра контекста. Таким образом, если контекст умирает (если активность - поворот экрана и т. Д.), AsyncTask не будет иметь сильной ссылки на него, и поэтому его можно будет собрать сборщиком мусора. Проверьте youtu.be/…

Шесть типов состояний достижимости объектов в Java:

  1. Сильные достижимые объекты - GC не будет собирать ( освобождает занятую память) объекты такого типа. Они достижимы через корневой узел или другой строго достижимый объект (то есть через локальные переменные, переменные класса, переменные экземпляра и т. Д.)
  2. Мягко достижимые объекты - GC может попытаться собрать этот тип объектов в зависимости от нехватки памяти. К ним можно получить доступ из корня через один или несколько мягких ссылочных объектов .
  3. Слабодоступные объекты - сборщик мусора должен собирать такие объекты. Эти доступны из корня через один или несколько слабых ссылочных объектов
  4. Восстанавливаемые объекты - сборщик мусора уже собирает эти объекты. Но они могут вернуться в одно из состояний - Сильное / Мягкое / Слабое при выполнении некоторого финализатора.
  5. Призрачный достижимый объект - GC уже собирает эти объекты и определил, что их нельзя воскресить ни одним финализатором (если он сам объявляет метод finalize (), то его финализатор будет запущен) . К ним можно получить доступ из корня через один или несколько фантомных ссылочных объектов .
  6. Недостижимый объект - объект не является ни сильно, ни мягко, ни слабо, ни фантомно достижимым, и его нельзя воскресить. Эти объекты готовы к рекультивации.
Плохое описание фантомных ссылок. Кроме того, вы перечислили 4 типа в особом порядке. «фантом» - это самый слабый тип, а не самый сильный. Традиционный порядок их перечисления - «сильный, мягкий, слабый, фантомный». И я понятия не имею, откуда у вас представление о том, что фантомные объекты используются для механизмов кеширования. AFAIK, это временное состояние, которое видит только сборщик мусора, а не то, с чем мог бы работать обычный программист. И все - извинения за пару вещей: 1. неправильное объяснение фантомных ссылок в предыдущей версии моего ответа и 2. задержка в исправлении ошибок. Теперь ответ улучшен за счет исправления ошибок.

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

Поведение кучи и сборщика мусора при большой нагрузке

  • Сильная / жесткая ссылка . По мере продолжения программы JVM не могла собрать сохраненный объект со строгой ссылкой. В конце концов оказался в «java.lang.OutOfMemoryError: пространство кучи Java»
  • Мягкая справка . По мере продолжения программы использование кучи продолжало расти, но сборщик мусора OLD-поколения случился, когда размер кучи приближался к максимальному. GC запустился немного позже по времени после запуска программы.
  • Слабая ссылка . При запуске программы объекты начали завершаться и собираться практически сразу. В основном объекты собирались при сборке мусора молодого поколения.
  • Фантомная ссылка . Как и в случае со слабой ссылкой, объекты, на которые есть фантомные ссылки, также начали немедленно завершаться и собираться мусор. Не было сборщика мусора старого поколения, и все объекты собирались в самой сборке мусора молодого поколения.

WeakReference : объекты, на которые имеются лишь слабые ссылки, собираются в каждом цикле сборки мусора (второстепенном или полном).

SoftReference : когда собираются только мягкие объекты, зависит от:

-XX: флаг SoftRefLRUPolicyMSPerMB = N (значение по умолчанию - 1000, или 1 секунда)

Количество свободной памяти в куче.

  • в куче 10 МБ свободного места (после полной сборки мусора);
  • -XX: SoftRefLRUPolicyMSPerMB = 1000

Затем объект, на который ссылается только SoftReference, будет собран, если последний раз, когда к нему обращались, больше 10 секунд.

Следует знать, что объект со слабыми ссылками будет собран только тогда, когда он имеет ТОЛЬКО слабые ссылки. Если у него есть хотя бы одна сильная ссылка, она не будет собрана, независимо от того, сколько у нее слабых ссылок.

Это здравый смысл . То же самое касается softref и phantomref.

Слабые ссылки собираются с нетерпением. Если сборщик мусора обнаруживает, что объект является слабо достижимым (достижимым только через слабые ссылки), он немедленно очищает слабые ссылки на этот объект. Как таковые, они хороши для хранения ссылки на объект, для которого ваша программа также хранит (с сильными ссылками) какую-то «связанную информацию», например, кэшированную информацию отражения о классе или оболочку для объекта и т. Д. Все, что делает нет смысла сохранять после того, как объект, с которым он связан, был GC-ed. Когда слабая ссылка очищается, она помещается в очередь ссылок, которую ваш код где-то опрашивает, а также отбрасывает связанные объекты. То есть вы сохраняете дополнительную информацию об объекте, но эта информация не нужна, когда объект, на который она ссылается, исчезает. Фактически, в определенных ситуациях вы даже можете создать подкласс WeakReference и сохранить связанную дополнительную информацию об объекте в полях подкласса WeakReference. Другое типичное использование WeakReference - вместе с Maps для хранения канонических экземпляров.

SoftReferences, с другой стороны, хороши для кэширования внешних, воссоздаемых ресурсов, поскольку GC обычно задерживает их очистку. Тем не менее, гарантируется, что все SoftReferences будут очищены до выброса OutOfMemoryError, поэтому теоретически они не могут вызвать OOME [*].

Типичный пример использования - сохранение проанализированной формы содержимого из файла. Вы бы реализовали систему, в которой вы загружали бы файл, анализировали его и сохраняли SoftReference для корневого объекта анализируемого представления. В следующий раз, когда вам понадобится файл, вы попытаетесь получить его через SoftReference. Если вы можете получить его, вы избавили себя от еще одной загрузки / синтаксического анализа, и если GC тем временем очистил его, вы перезагружаете его. Таким образом, вы используете свободную память для оптимизации производительности, но не рискуете OOME.

Теперь о [*]. Сохранение SoftReference само по себе не может вызвать OOME. Если, с другой стороны, вы по ошибке используете SoftReference для задачи, для которой предназначен WeakReference (а именно, вы сохраняете информацию, связанную с объектом, как-то сильно привязанную к объекту, и отбрасываете ее, когда объект Reference очищается), вы можете запустить OOME как ваш код, который опрашивает ReferenceQueue и отбрасывает связанные объекты, может не выполняться своевременно.

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

Читайте также: