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

749

В чем разница между java.lang.ref.WeakReference и java.lang.ref.SoftReference?

  • 8
    SoftReferences - это тип (не совсем, но для обсуждения) WeakReferences, которые обычно собираются, когда JVM считает, что не хватает памяти.
  • 2
    @AjeetGanga, Слабые слабые ссылки всегда собираются при каждом запуске GC. См. Stackoverflow.com/a/46291143/632951
Теги:
reference
weak-references
soft-references

12 ответов

821
Лучший ответ

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

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

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

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. Один размер не подходит для всех.

  • 5
    Сообщение больше не доступно, вы можете найти его на обратном пути: web.archive.org/web/20061130103858/http://weblogs.java.net/blog/…
  • 0
    на этот раз архив больше не доступен
203

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

  • 12
    Особенно полезно для объяснения того, когда будут использоваться слабые объекты.
  • 0
    Ключевым моментом в отношении правильного использования WeakReference является то, что в тех местах, где его следует использовать, тот факт, что он может оставаться действительным в течение некоторого времени после того, как ссылка выходит из области видимости, может быть допустимым, но нежелательным.
Показать ещё 4 комментария
126

В Java; от сильнейших до самых слабых, есть: Сильные, Мягкие, Слабые и Phantom

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

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

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

A Phantom ссылка - это ссылка на объект с фантомной ссылкой после того, как она была завершена, но до того, как выделенная память была исправлена.

Источник

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

  • Когда король Сильный, GC не может его убить.
  • Когда король Мягкий, GC атакует его, но король управляет королевством с защитой до тех пор, пока не будет доступен ресурс.
  • Когда король Слабый, GC атакует его, но правит королевством без защиты.
  • Когда король Phantom, GC уже убил его, но король доступен через его душу.
  • 5
    Мягкая ссылка ... 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 ?
  • 0
    да, сборщик мусора не будет собирать ссылку, пока не освободится память.
Показать ещё 3 комментария
72

Слабая ссылка 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
    Вы можете получить NullPointerException в aMap.get().put(...) .
  • 0
    Ваш первый пример HashMap выглядит неправильно. Когда вы делаете «aMap.put (emp, val);» и emp, и val являются сильными ссылками. Внутри создается новая переменная для хранения «emp» и «val», поэтому, когда вы делаете «emp = null;» вы просто обнуляете переменную emp, но не внутреннюю переменную для хэш-карты (которая все еще содержит исходный объект Employee). Следовательно, хеш-карта будет по-прежнему содержать сильную ссылку на emp, независимо от того, что вы делаете с переменной emp снаружи.
Показать ещё 3 комментария
45

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

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

21

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

  • 9
    Но в Android это не рекомендуется для кешей developer.android.com/reference/java/lang/ref/…
  • 4
    @DoctororDrive, вопрос был о Java, а не о Dalvik! :-П
Показать ещё 1 комментарий
7

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

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

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

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

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


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

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

  • бесполезный хак для реализации softreference с приоритетом 2, такой, что вам не нужно писать его, но он не работает должным образом, потому что кеш будет очищаться при каждом запуске GC, даже если есть запасная память. См. https://stackoverflow.com/questions/3243215/how-to-use-weakreference-in-java-and-android-development для фаз. (Кроме того, что если вам нужно более 2 уровней приоритета кеша? Для этого вам все равно нужна настоящая библиотека.)

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

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

  • 0
    А как насчет кеша, в котором тип ключа equals() - это просто идентификатор объекта? Мягкие ссылки там кажутся пустой тратой, потому что, как только ключевой объект перестает быть сильно доступным, никто никогда не будет искать это отображение снова.
  • 0
    Я не согласен. Используйте WeakReference, если вы не хотите каким-либо образом влиять на GC (возможно, вы захотите сохранить ссылку на объект, а затем проверить, существует ли она по-прежнему, без каких-либо предпочтений). Используйте SoftReference, если вы хотите повлиять на GC, чтобы попытаться сохранить объект (т. Е. Когда вы предпочитаете, чтобы GC сохранял его).
Показать ещё 1 комментарий
4

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


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

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

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


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

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

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


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

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

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

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

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

3

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

  • Сильные доступные объекты - GC не будет собирать (вернуть память, занятую) такими типами объектов. Они доступны через root node или другой объект с высокой степенью доступности (т.е. Через локальные переменные, переменные класса, переменные экземпляра и т.д.).
  • Мягкие доступные объекты - GC может попытаться собрать такие объекты в зависимости от конкуренции памяти. Они доступны из корня через один или несколько мягких ссылочных объектов
  • Слабые доступные объекты - GC должен собирать такие объекты. Эти достижимы из корня через один или несколько слабых опорных объектов
  • Объекты с воскрешением - GC уже находится в процессе сбора этих объектов. Но они могут вернуться в одно из состояний - Сильное/Мягкое/Слабое путем выполнения некоторого финализатора
  • Phantom доступный объект - GC уже находится в процессе сбора этих объектов и решил не быть воскрешенным любым финализатором (если он объявляет finalize() сам метод, тогда его финализатор будет запущен). Они доступны из корня через один или несколько опорных объектов phantom
  • Недостижимый объект. Объект не является ни сильно, мягко, слабо, ни phantom недоступен, и не может быть воскрешен. Эти объекты готовы к рекультивации.

Подробнее: https://www.artima.com/insidejvm/ed2/gc16.html" collapse

  • 4
    Не хорошее описание фантомных ссылок. Кроме того, вы перечислили 4 типа в особом порядке. «Призрак» - самый слабый тип, а не самый сильный тип. Традиционный порядок перечисления это "сильный, мягкий, слабый, призрачный". И я понятия не имею, откуда у вас представление о том, что фантомные объекты используются для механизмов кэширования. AFAIK, это временное состояние, видимое только GC, а не то, с чем будет работать обычный программист.
  • 0
    @ToolmakerSteve и все - извиняюсь за пару вещей 1. неправильное объяснение ссылок на фантом в предыдущей версии моего ответа, и 2. задержка в исправлении ошибок. Теперь ответ был улучшен путем исправления ошибок
1

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

Когда есть одна или несколько ссылок на объект, это не будет мусор, собранный на 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 немного сильнее, чем слабая ссылка. Мягкая ссылка позволяет собирать мусор, но просит сборщика мусора очистить его, только если нет другого варианта. То есть, он имеет право на сбор мусора, но сборщик мусора может удалить его на основе хруста памяти. Если он оставлен с небольшой памятью и он может восстановить память, тогда он будет собирать мягкие ссылки.
0

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

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

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

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

    Пример:

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

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

0

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

  • 0
    Это здравый смысл ... то же самое касается softref и фантома.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню