Какая разница между SoftReference и WeakReference в Java?
В чем разница между java.lang.ref.WeakReference
и java.lang.ref.SoftReference
?
Ответы
Ответ 1
Из понимания слабых ссылок, Итан Николас:
Слабые ссылки
Проще говоря, слабая ссылка - это ссылка, которая недостаточно сильна, чтобы заставить объект оставаться в памяти. Слабые ссылки позволяют вам использовать возможность сборщика мусора, чтобы определить достижимость для вас, поэтому вам не придется делать это самостоятельно. Вы создаете слабую ссылку, как это:
WeakReference weakWidget = new WeakReference(widget);
а затем в другом месте кода вы можете использовать weakWidget.get()
чтобы получить реальный объект Widget
. Конечно, слабая ссылка недостаточно сильна, чтобы предотвратить вывоз мусора, так что вы можете найти (если нет сильных ссылок на виджет), который weakWidget.get()
вдруг начинает возвращение null
.
...
Мягкие ссылки
Мягкая ссылка точно такая же, как и слабая, за исключением того, что она меньше стремится выбросить объект, на который она ссылается. Объект, который является только слабо достижимым (самые сильные ссылки на него - WeakReferences
), будет отброшен в следующем цикле сборки мусора, но объект, который является легко достижимым, обычно остается на некоторое время.
SoftReferences
не обязаны вести себя иначе, чем WeakReferences
, но на практике объекты с WeakReferences
обычно сохраняются, пока памяти в изобилии. Это делает их отличной основой для кэша, такого как описанный выше кэш изображений, поскольку вы можете позволить сборщику мусора беспокоиться как о достижимости объектов (объект с высокой степенью доступности никогда не будет удален из кэша), так и о том, насколько плохо нужна память, которую они потребляют.
А Питер Кесслер добавил в комментарии:
Sun JRE относится к SoftReferences иначе, чем к WeakReferences. Мы пытаемся удержать объект, на который ссылается SoftReference, если нет давления на доступную память. Одна деталь: политика в отношении JRE "-client" и "-server" различна: JRE -client старается сохранить небольшой размер, предпочитая очищать SoftReferences, а не расширять кучу, тогда как JRE -server пытается поддерживать высокую производительность, предпочитая расширять кучу (если возможно), а не очищать SoftReferences. Один размер не подходит для всех.
Ответ 2
Слабые ссылки собираются с нетерпением. Если GC обнаружит, что объект
слабодоступный (доступный только через слабые ссылки), он очистит
слабые ссылки на этот объект немедленно. Таким образом, они хороши для
сохраняя ссылку на объект, для которого ваша программа также поддерживает
(строго ссылка) "связанная информация", например, как кешированная
информация отражения о классе или обертка для объекта и т.д.
Все, что не имеет смысла держать после связанного с ним объекта
с GC-ed. Когда слабая ссылка очищается, она попадает в очередь
что ваш код опроса где-то, и он отбрасывает
связанных объектов. То есть вы сохраняете дополнительную информацию о
объект, но эта информация не нужна, как только объект, на который он ссылается
уходит. Собственно, в определенных ситуациях вы можете даже подклассы
WeakReference и сохранить дополнительную информацию об объекте
в полях подкласса WeakReference. Другое типичное использование
WeakReference в сочетании с Maps для хранения канонических экземпляров.
SoftReferences, с другой стороны, хороши для кэширования внешних, восстанавливаемых ресурсов
поскольку GC обычно задерживает их очистку. Это гарантировано, хотя все
SoftReferences будет очищен до того, как OutOfMemoryError будет выброшен, поэтому они
теоретически не может вызвать OOME [*].
Типичным примером использования является сохранение разобранной формы содержимого из
файл. Вы бы внедрили систему, в которой вы загрузили файл, проанализировали его и сохранили
SoftReference к корневому объекту анализируемого представления. В следующий раз
вам нужен файл, вы попытаетесь получить его через SoftReference. Если
вы можете получить его, вы позаботились о другом загрузке/анализе, и если GC
очистив его, вы его перезагрузите. Таким образом, вы используете бесплатно
памяти для оптимизации производительности, но не рискуйте OOME.
Теперь для [*]. Сохранение SoftReference не может вызвать OOME сам по себе. Если
с другой стороны, вы ошибочно используете SoftReference для задачи, для которой подразумевается WeakReference
(а именно, вы сохраняете информацию, связанную с объектом как-то
сильно ссылаются и отбрасывают его, когда объект Reference получает
очищено), вы можете запустить OOME как свой код, который опросит ReferenceQueue
и отбрасывает связанные объекты, которые могут не выполняться своевременно
мода.
Таким образом, решение зависит от использования
- если вы кэшируете информацию, которая стоит дорого, но
тем не менее, восстанавливаются из других данных, используют мягкие ссылки
- если вы сохраняете ссылку на канонический экземпляр некоторых данных или
вы хотите иметь ссылку на объект без "владения" им (таким образом
препятствуя тому, чтобы он был GC'd), используйте слабую ссылку.
Ответ 3
В Java; от сильнейших до самых слабых, есть: Сильные, Мягкие, Слабые и Phantom
A Сильная ссылка - это нормальная ссылка, которая защищает выделенный объект от коллекции GC. т.е. никогда не собирать мусор.
A Мягкая ссылка подходит для сбора сборщиками мусора, но, вероятно, ее не собирают, пока ее память не понадобится. т.е. сбор мусора перед OutOfMemoryError
.
A Слабая ссылка - это ссылка, которая не защищает ссылочный объект от коллекции GC. т.е. мусор собирает, когда нет сильных или мягких ссылок.
A Phantom ссылка - это ссылка на объект с фантомной ссылкой после того, как она была завершена, но до того, как выделенная память была исправлена.
Источник
Аналогия: Предположим, что JVM является королевством, Object является королем королевства, а GC является атакующим королевства, которое пытается убить короля (объекта).
- Когда король Сильный, GC не может его убить.
- Когда король Мягкий, GC атакует его, но король управляет королевством с защитой до тех пор, пока не будет доступен ресурс.
- Когда король Слабый, GC атакует его, но правит королевством без защиты.
- Когда король Phantom, GC уже убил его, но король доступен через его душу.
Ответ 4
Слабая ссылка
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Принцип: weak reference
связан с сборкой мусора. Обычно объект, имеющий один или более reference
, не будет иметь права на сбор мусора.
Вышеприведенный принцип не применим, если он weak reference
. Если объект имеет только слабую ссылку с другими объектами, то он готов к сбору мусора.
Посмотрим на приведенный ниже пример. У нас есть Map
с объектами, где Key ссылается на объект.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Теперь, во время выполнения программы мы сделали emp = null
. Клавиша Map
, удерживающая клавишу, здесь не имеет смысла, так как она null
. В приведенной выше ситуации объект не собирает мусор.
WeakHashMap
WeakHashMap
- это тот, где записи (key-to-value mappings
) будут удалены, когда их невозможно будет извлечь из Map
.
Позвольте мне показать вышеприведенный пример с WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Результат: Взял 20 calls to System.gc()
, чтобы получить результат aMap size
of: 0.
WeakHashMap
имеет только слабые ссылки на ключи, а не сильные ссылки, такие как другие классы Map
. Есть ситуации, о которых вам нужно позаботиться, когда значение или ключ сильно привязаны, хотя вы использовали WeakHashMap
. Этого можно избежать, обернув объект в WeakReference.
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
Мягкие ссылки.
Soft Reference
немного сильнее, чем слабая ссылка. Мягкая ссылка позволяет собирать мусор, но просит сборщика мусора очистить его, только если нет другого варианта.
Сборщик мусора не агрессивно собирает объекты с доступной мишенью так, как это делается со слабодоступными, вместо этого он собирает только объекты с достижением цели, если он действительно "нуждается" в памяти. Мягкие ссылки - это способ сказать сборщику мусора: "Пока память не слишком тугая, я хотел бы держать этот объект вокруг. Но если память становится очень напряженной, продолжайте и собирайте ее, и я буду заниматься с этим". Сборщик мусора должен очистить все мягкие ссылки, прежде чем он может бросить OutOfMemoryError
.
Ответ 5
Единственная реальная разница между мягкой ссылкой и слабой ссылкой заключается в том, что
сборщик мусора использует алгоритмы, чтобы решить, возвращать или нет возвращать легко достижимый объект, но всегда восстанавливает слабо достижимый объект.
Ответ 6
SoftReference
предназначен для кэшей. Когда будет найдено, что a WeakReference
ссылается на другой недостижимый объект, тогда он будет немедленно очищен. SoftReference
может быть оставлено как есть. Как правило, существует некоторый алгоритм, относящийся к количеству свободной памяти и времени, которое было использовано для определения того, должно ли оно быть очищено. Текущий алгоритм Sun заключается в очистке ссылки, если она не использовалась в течение нескольких секунд, так как в куче Java есть мегабайты свободной памяти (настраивается, сервер HotSpot проверяет максимальную возможную кучу как установленную -Xmx
). SoftReference
будет очищен до того, как будет сброшен OutOfMemoryError
, если не достигнуто другое.
Ответ 7
Эта статья может быть очень полезна для понимания сильных, мягких, слабых и фантомных ссылок.
Чтобы дать вам резюме,
Если у вас есть только слабые ссылки на объект (без сильных ссылок), то объект будет восстановлен GC в самом следующем цикле GC.
Если у вас есть только мягкие ссылки на объект (без сильных ссылок), то объект будет возвращен GC только тогда, когда JVM не хватит памяти.
Таким образом, вы можете сказать, что сильные ссылки имеют максимальную силу (никогда не могут быть собраны GC)
Мягкие ссылки более эффективны, чем слабые (поскольку они могут избежать цикла GC, пока JVM не исчерпает память)
Слабые ссылки даже менее мощны, чем мягкие ссылки (так как они не могут спровоцировать какой-либо цикл GC и будут исправлены, если у объекта нет другой сильной ссылки).
Ресторанная аналогия
- Официант - GC
- Вы - Объект в куче
- Зона ресторана/пространство - куча места
- Новый клиент - новый объект, который хочет столик в ресторане
Теперь, если вы являетесь сильным клиентом (аналог сильной рекомендации), то даже если в ресторан приходит новый клиент или что-то такое, что когда-либо радует, вы никогда не покинете свой стол (область памяти в куче). Официант не имеет права говорить вам (или даже просить вас) покинуть ресторан.
Если вы мягкий клиент (аналог мягкого отзыва), то, если в ресторан приходит новый клиент, официант не будет просить вас покинуть стол, если не осталось другой пустой таблицы для размещения нового клиента. (Другими словами, официант попросит вас покинуть стол только в том случае, если заходит новый клиент, и для этого нового клиента не осталось другой таблицы)
Если вы слабый клиент (аналог слабой ссылки), тогда официант по своему желанию может (в любой момент) попросить вас покинуть ресторан: P
Ответ 8
Единственная реальная разница
Согласно документу, свободные WeakReferences должны быть очищены работающим GC.
Согласно документу, свободные SoftReferences должны быть очищены, прежде чем OOM выбрасывается.
Это единственная реальная разница. Все остальное не является частью договора. (Я предполагаю, что последние документы являются договорными.)
SoftReferences полезны. Кэши, чувствительные к памяти, используют SoftReferences, а не WeakReferences.
Единственное правильное использование WeakReference - наблюдать за запуском GC. Вы делаете это путем создания новой WeakReference, чей объект немедленно выходит из области видимости, а затем пытаетесь получить значение null из weak_ref.get()
. Когда он null
, вы узнаете, что между этой продолжительностью GC запускается. Что касается неправильного использования WeakReference, список бесконечен:
-
бесполезный хак для реализации softreference с приоритетом 2, такой, что вам не нужно писать его, но он не работает должным образом, потому что кеш будет очищаться при каждом запуске GC, даже если есть запасная память. См. fooobar.com/questions/23394/... для фаз. (Кроме того, что если вам нужно более 2 уровней приоритета кеша? Для этого вам все равно нужна настоящая библиотека.)
-
паршивый хак, чтобы связать данные с объектом существующего класса, но он создает утечку памяти (OutOfMemoryError), когда ваш GC решает сделать перерыв после создания ваших слабых ссылок. Кроме того, это ужасно: лучший подход - использовать кортежи.
-
паршивое хакерство, связывающее данные с объектом существующего класса, где класс имеет смелость сделать себя не подклассифицированным и используется в существующем коде функции, который вам нужно вызвать. В таком случае правильное решение состоит в том, чтобы либо отредактировать класс и сделать его подклассифицированным, либо отредактировать функцию и заставить ее использовать интерфейс вместо класса, либо использовать альтернативную функцию.
Ответ 9
Шесть типов состояний достижимости объекта в Java -
- Сильные доступные объекты - GC не будет собирать (вернуть память, занятую) такими типами объектов. Они доступны через root node или другой объект с высокой степенью доступности (т.е. Через локальные переменные, переменные класса, переменные экземпляра и т.д.).
- Мягкие доступные объекты - GC может попытаться собрать такие объекты в зависимости от конкуренции памяти. Они доступны из корня через один или несколько мягких ссылочных объектов
- Слабые доступные объекты - GC должен собирать такие объекты. Эти
достижимы из корня через один или несколько слабых опорных объектов
- Объекты с воскрешением - GC уже находится в процессе сбора этих объектов. Но они могут вернуться в одно из состояний - Сильное/Мягкое/Слабое путем выполнения некоторого финализатора
- Phantom доступный объект - GC уже находится в процессе сбора этих объектов и решил не быть воскрешенным любым финализатором (если он объявляет finalize() сам метод, тогда его финализатор будет запущен). Они доступны из корня через один или несколько опорных объектов phantom
- Недостижимый объект. Объект не является ни сильно, мягко, слабо, ни phantom недоступен, и не может быть воскрешен. Эти объекты готовы к рекультивации.
Подробнее: https://www.artima.com/insidejvm/ed2/gc16.html" collapse
Ответ 10
Следует помнить, что объект с низкой ссылкой будет собираться только тогда, когда он имеет ТОЛЬКО слабые ссылки. Если у него есть одна сильная ссылка, она не собирается, независимо от того, сколько ее слабых ссылок.
Ответ 11
Слабая ссылка
Когда есть одна или несколько ссылок на объект, это не будет мусор, собранный на Java. Но это правило зависит от типа ссылки. Если объект имеет только слабую ссылку, связанную с другими объектами, то он является допустимым кандидатом на сбор мусора.
Давайте рассмотрим примерный сценарий, чтобы лучше понять его. Пусть TextView будет объектом (недавно программирование на Android и, таким образом, с использованием его класса, например:-)), и у нас будут запрограммированные идентификаторы, используемые для его идентификации. Эти идентификаторы используются в каком-либо другом объекте для ссылки на TextViews.
...
Map textViewIdMap = new HashMap();
textViewIdMap.put(textView1, iD1);
textViewIdMap.put(textView2, iD2)
...
ключ - это объект TextView, а значение - это идентификатор. Теперь во время выполнения программы мы удалили объект TextView textView1. Мы не требуем этого объекта view, поэтому мы сделали его нулевым. Теперь, что произойдет с парой ключ-значение (textView1, iD1), хранящейся в HashMap. Эта пара на данный момент не имеет смысла, и она не требуется, поскольку это текстовое изображение является нулевым.
Итак, программным мы должны убедиться, что, когда textView будет удален, его соответствующая запись на карте должна быть удалена. Только тогда этот объект становится кандидатом на сбор мусора. В противном случае, несмотря на то, что он не используется во время выполнения, этот устаревший объект не будет собирать мусор.
Soft Reference
Soft Reference немного сильнее, чем слабая ссылка. Мягкая ссылка позволяет собирать мусор, но просит сборщика мусора очистить его, только если нет другого варианта. То есть, он имеет право на сбор мусора, но сборщик мусора может удалить его на основе хруста памяти. Если он оставлен с небольшой памятью и он может восстановить память, тогда он будет собирать мягкие ссылки.
Ответ 12
WeakReference: объекты, которые только слабо ссылаются, собираются в каждом цикле GC (незначительные или полные).
SoftReference: когда собираются объекты, которые только мягко ссылаются, зависит от:
-
-XX: SoftRefLRUPolicyMSPerMB = флаг N (значение по умолчанию равно 1000, ака 1 секунда)
-
Количество свободной памяти в куче.
Пример:
- куча имеет 10 МБ свободного места (после полного GC);
- -XX: SoftRefLRUPolicyMSPerMB = 1000
Тогда объект, на который ссылается только SoftReference, будет собран, если последний раз, когда он был достигнут, будет больше 10 секунд.
Ответ 13
Чтобы показать аспект использования памяти в действии, я провел эксперимент с Strong, Soft, Weak & Призрачные ссылки под тяжелой нагрузкой с тяжелыми объектами, сохраняя их до конца программы. Затем контролировал использование кучи & GC поведение. Эти показатели могут варьироваться от случая к случаю, но, безусловно, дают понимание высокого уровня. Ниже приведены результаты.
Куча & Поведение GC под большой нагрузкой
- Сильная/Жесткая ссылка - Во время продолжения программы JVM не смогла собрать сохраненный объект с сильной ссылкой. В конечном итоге это привело к "java.lang.OutOfMemoryError: пространство кучи Java"
- Soft Reference - По мере продолжения программы использование кучи продолжало расти, но GD OLD gen случалось, когда оно приближалось к максимальной куче. GC начал немного позже после запуска программы.
- Слабая ссылка - Когда программа началась, объекты начали завершаться & собирать почти сразу. Главным образом объекты были собраны в сборке мусора молодого поколения.
- Фантомная ссылка - Подобно слабой ссылке, объекты с фантомной ссылкой также начали дорабатываться & мусор собрал сразу. Там не было старого поколения GC & все объекты собирались в самой сборке мусора молодого поколения.
Вы можете получить более подробные графики, статистику, наблюдения для этого эксперимента здесь.