В чем разница между SoftReference и WeakReference в Java?

Какая разница?

11 ответов

Решение

От понимания слабых ссылок, Итан Николас:

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

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

WeakReference weakWidget = new WeakReference(widget);

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

...

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

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

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

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

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

Слабые ссылки собраны с нетерпением. Если 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), использовать слабую ссылку.

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

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

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

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

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

Источник

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

  • Когда король сильный, GC не может убить его.
  • Когда King is Soft, GC атакует его, но King управляет королевством с защитой, пока ресурс не станет доступным.
  • Когда Король слаб, GC атакует его, но управляет королевством без защиты.
  • Когда король Призрак, GC уже убил его, но король доступен через его душу.

Слабая ссылка http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

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

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

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 из: 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,

Единственная реальная разница между мягкой ссылкой и слабой ссылкой заключается в том, что

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

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

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


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

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

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


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

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

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


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

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

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

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

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

Шесть типов достижимости объектов в Java -

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

Для получения более подробной информации: https://www.artima.com/insidejvm/ed2/gc16.html "свернуть

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

Согласно документу, свободные WeakReferences должны быть очищены работающим GC.

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

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

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


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

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

  • бесполезный хак для реализации softreference с приоритетом 2, такой, что вам не нужно писать его, но он не работает должным образом, потому что кеш будет очищаться при каждом запуске GC, даже если есть запасная память. См. /questions/35123562/kak-ispolzovat-weakreference-v-razrabotke-java-i-android/35123572#35123572 для фаз. (Кроме того, что, если вам нужно более 2 уровней приоритета кэша? Для этого вам все равно нужна настоящая библиотека.)

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

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

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

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

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

Вы можете получить более подробные графики, статистику и наблюдения для этого эксперимента здесь.

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

Слабая ссылка

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

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

...
Map textViewIdMap = new HashMap();
textViewIdMap.put(textView1, iD1);
textViewIdMap.put(textView2, iD2)
...


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

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


Soft Reference

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

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

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

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

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

    Пример:

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

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

Другие вопросы по тегам