Java: разница между сильной / мягкой / слабой / фантомной ссылкой
Я читал эту статью на эту тему, но я не совсем понимаю. Пожалуйста, дайте мне несколько советов вместе с примерами при описании концепций.
6 ответов
Java предоставляет два разных типа / класса ссылочных объектов: сильный и слабый. Слабые эталонные объекты можно далее разделить на мягкие и фантомные. Давайте идти по пунктам.
Сильный Ссылочный Объект
StringBuilder builder = new StringBuilder();
Это тип / класс ссылочного объекта по умолчанию, если не указано иное: builder
является сильным эталонным объектом. Этот вид ссылки делает указанный объект непригодным для GC. То есть всякий раз, когда на объект ссылается цепочка сильных ссылочных объектов, он не может быть собран мусором.
Слабый эталонный объект
WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);
Слабые ссылочные объекты не являются типом / классом ссылочных объектов по умолчанию, и для их использования они должны быть явно указаны, как в приведенном выше примере. Этот вид ссылки делает эталонный объект пригодным для GC. То есть в случае единственной доступной ссылки для StringBuilder
объект в памяти, на самом деле, является слабой ссылкой, тогда GC разрешено собирать мусор StringBuilder
объект. Когда объект в памяти доступен только слабым ссылочным объектам, он автоматически получает право на сборку мусора.
Уровни слабости
Можно задействовать два разных уровня слабости: мягкий и призрачный.
Мягкий эталонный объект в основном является слабым эталонным объектом, который остается в памяти немного больше: обычно он сопротивляется циклу GC до тех пор, пока не станет доступной память, и нет риска OutOfMemoryError
(в этом случае его можно удалить).
С другой стороны, фантомный ссылочный объект полезен только для того, чтобы точно знать, когда объект был эффективно удален из памяти: обычно они используются для исправления странного поведения возрождения / воскрешения finalize(), поскольку они фактически не возвращают сам объект, но только помощь в отслеживании их присутствия в памяти.
Слабые ссылочные объекты идеально подходят для реализации модулей кеша. Фактически, может быть реализовано своего рода автоматическое выселение, позволяющее ГХ очищать области памяти всякий раз, когда объекты / значения больше не достижимы цепочкой сильных ссылок. Примером является WeakHashMap, сохраняющий слабые ключи.
Слабая ссылка:
Проще говоря, слабая ссылка - это ссылка, которая недостаточно сильна, чтобы заставить объект остаться в памяти. Слабые ссылки позволяют вам использовать способность сборщика мусора определять доступность для вас, поэтому вам не придется делать это самостоятельно.
Мягкая ссылка:
Мягкая ссылка точно так же, как слабая ссылка, за исключением того, что она меньше стремится выбросить объект, на который она ссылается. Объект, который является только слабо достижимым (самые сильные ссылки на него - WeakReferences), будет отброшен в следующем цикле сборки мусора, но объект, который является легко достижимым, обычно остается на некоторое время.
Призрачный
Фантомная ссылка совершенно отличается от SoftReference или WeakReference. Его захват его объекта настолько слаб, что вы даже не можете получить объект - его метод get() всегда возвращает ноль. Единственное использование для такой ссылки - отслеживание того, когда она помещается в ReferenceQueue, так как в этот момент вы знаете, что объект, на который она указала, мертв.
Этот текст был извлечен из: https://weblogs.java.net/blog/2006/05/04/understanding-weak-references
Эта статья может быть очень полезна для понимания сильных, мягких, слабых и фантомных ссылок.
Чтобы дать вам резюме,
Если у вас есть сильная ссылка на объект, то этот объект никогда не может быть собран / утилизирован GC (сборщик мусора).
Если у вас есть только слабые ссылки на объект (без сильных ссылок), то объект будет восстановлен GC в следующем цикле GC.
Если у вас есть только мягкие ссылки на объект (без сильных ссылок), то объект будет восстановлен GC только тогда, когда JVM не хватит памяти.
Мы создаем фантомные ссылки на объект, чтобы отслеживать, когда объект помещается в очередь в ReferenceQueue
, Как только вы узнаете, что можете выполнить детальную финализацию. (Это избавит вас от случайного воскрешения объекта, так как фантомные ссылки не дают вам рефератов). Я бы посоветовал вам прочитать эту статью, чтобы получить более подробную информацию об этом.
Таким образом, вы можете сказать, что сильные ссылки имеют максимальную силу (никогда не могут быть собраны GC)
Мягкие ссылки более эффективны, чем слабые (поскольку они могут избежать цикла GC до тех пор, пока JVM не исчерпает память)
Слабые ссылки даже менее мощны, чем мягкие ссылки (поскольку они не могут спровоцировать какой-либо цикл GC и будут исправлены, если у объекта нет другой сильной ссылки).
Ресторанная аналогия
- Официант - GC
- Вы - Объект в куче
- Зона ресторана / пространство - куча места
- Новый клиент - новый объект, который хочет столик в ресторане
Теперь, если вы являетесь сильным клиентом (аналог сильной рекомендации), то даже если в ресторан приходит новый клиент или что-то такое, что всегда радует, вы никогда не покинете свой стол (область памяти в куче). Официант не имеет права говорить вам (или даже просить вас) покинуть ресторан.
Если вы мягкий клиент (аналог мягкого отзыва), то если в ресторан приходит новый клиент, официант не будет просить вас покинуть стол, если не осталось другой пустой таблицы для размещения нового клиента. (Другими словами, официант попросит вас покинуть стол только в том случае, если заходит новый клиент, и для этого нового клиента не осталось другой таблицы)
Если вы слабый клиент (аналог слабой ссылки), тогда официант по своему желанию может (в любой момент) попросить вас покинуть ресторан:P
Простая разница между SoftReference
а также WeakReference
предоставляется разработчиком Android.
Разница между SoftReference
и WeakReference
момент времени, в который принято решение очистить и поставить в очередь ссылку:
SoftReference
следует очищать и ставить в очередь как можно позже, то есть в случае, если виртуальной машине угрожает нехватка памяти.WeakReference
может быть очищен и помещен в очередь, как только известно, что на него слабо ссылаются.
Три термина, которые вы использовали, в основном связаны с правом объекта на сбор мусора.
Слабая ссылка:: Это ссылка, которая недостаточно сильна, чтобы заставить объект оставаться в памяти. Это прихоть сборщика мусора для сбора этого объекта для сбора мусора.Вы не можете заставить этот GC не собирать его.
Мягкая ссылка:: Это более-менее похоже на слабую ссылку. Но вы можете сказать, что он удерживает объект немного сильнее, чем слабая ссылка из сборки мусора.
Если сборщики мусора собирают слабые ссылки в самом первом жизненном цикле, они собирают мягкие ссылки в следующем цикле сбора мусора.
Сильная ссылка:: Это прямо противоположно двум вышеупомянутым ссылкам. Они меньше любят собирать мусор (в основном они никогда не собираются).
Вы можете обратиться к следующей ссылке для получения дополнительной информации:
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html
Сильные Ссылки
Это ваши обычные ссылки на объекты, которые мы кодируем ежедневно:
Employee emp = new Employee();
Переменная "emp" содержит строгую ссылку на объект Employee, а объекты, доступные через любую цепочку строгих ссылок, не могут быть использованы для сборки мусора. Обычно это то, что вы хотите, но не всегда. Теперь предположим, что мы выбираем большое количество сотрудников из базы данных в коллекции или на карте, и нам нужно регулярно обрабатывать их, поэтому для поддержания производительности мы будем держать их в кэше.
Насколько это хорошо, но теперь нам нужны разные данные, и нам не нужны эти объекты Employee, и на них нет ссылок нигде, кроме кеша. Что вызывает утечку памяти, потому что эти объекты не используются, но все еще не подходят для сборки мусора, и мы не можем удалить эти объекты из кэша, потому что у нас нет ссылки на них? Так что здесь либо нам нужно очистить весь кеш вручную, что утомительно, либо мы могли бы использовать ссылки другого типа, например, Weak References.
Слабые ссылки
Слабая ссылка не закрепляет объект в памяти, и в следующем цикле GC она будет GC, если на нее не ссылаются другие ссылки. Мы можем использовать класс WeakReference, предоставляемый Java, для создания кэшей указанного выше типа, которые не будут хранить объекты, на которые нет ссылок откуда-либо еще.
WeakReference<Cache> cache = new WeakReference<Cache>(data);
Для доступа к данным вам нужно вызвать cache.get(). Этот вызов get может вернуть null, если слабая ссылка была собрана сборщиком мусора: вы должны проверить возвращаемое значение, чтобы избежать NPE. Java предоставляет коллекции, которые используют слабые ссылки, например, класс WeakHashMap хранит ключи (не значения) как слабые ссылки. Если ключ GC'd, то значение будет автоматически удалено и с карты.
Поскольку слабые ссылки также являются объектами, нам нужен способ их очистки (они больше не нужны, когда объект, на который они ссылались, был GC'd). Если вы передадите ReferenceQueue в конструктор для слабой ссылки, сборщик мусора добавит эту слабую ссылку к ReferenceQueue до того, как они будут завершены или GC'd. Вы можете периодически обрабатывать эту очередь и обрабатывать мертвые ссылки.
Мягкие ссылки
Soft Reference похож на WeakReference, но он с меньшей вероятностью будет собирать мусор. Мягкие ссылки очищаются по усмотрению сборщика мусора в ответ на запрос памяти. Виртуальная машина гарантирует, что все мягкие ссылки на мягко достижимые объекты будут очищены до того, как она выдаст ошибку OutOfMemoryError.
Призрачные Ссылки
Фантомные ссылки - самый слабый из всех ссылочных типов, вызов get для них всегда будет возвращать ноль. На объект ссылаются фантомно после того, как он был завершен, но до того, как его выделенная память была освобождена, в отличие от слабых ссылок, которые ставятся в очередь до того, как они завершены, или ссылки фантома GC'd редко используются.
Так чем они полезны? Когда вы создаете фантомную ссылку, вы всегда должны передавать ReferenceQueue. Это означает, что вы можете использовать фантомную ссылку, чтобы увидеть, когда ваш объект GC'd.
Эй, так что, если слабые ссылки ставятся в очередь, когда они считаются финализированными, но еще не GC'd, мы могли бы создать новую сильную ссылку на объект в блоке финализатора и предотвратить объект GC'd. Да, вы можете, но вы, вероятно, не должны этого делать. Для проверки этого случая цикл GC будет происходить как минимум дважды для каждого объекта, если этот объект не доступен только по фантомной ссылке. Вот почему вы можете исчерпать кучу, даже если ваша память содержит много мусора. Призрачные ссылки могут предотвратить это.
4 степени референции - Strong, Weak, Soft, Phantom
Сильный - это своего рода ссылка, которая делает указанный объект неподходящим для GC. Занятия строителей. Например - StringBuilder
Слабый - это ссылка, которая имеет право на GC.
Soft - это своего рода ссылка, объект которой подходит для GC, пока память не станет доступной. Лучше всего для кеша изображений. Он будет держать их до тех пор, пока память не станет доступной.
Фантом - это своего рода ссылка, объект которой имеет прямое право на сборщик мусора. Используется только для того, чтобы узнать, когда объект удален из памяти.
использует:
Позволяет определить, когда объект точно удаляется из памяти.
когда
finalize()
метод перегружен, тогда GC может не произойти своевременно для GC подходящих объектов двух классов. Так что призрачная ссылка делает их подходящими для GC доfinalize()
Вот почему вы можете получить OutOfMemoryErrors, даже если большая часть кучи является мусором.
Слабые ссылки идеально подходят для реализации модулей кеша.