JavaRush /Java блог /Архив info.javarush /Отличия между слабыми, мягкими, фантомными и обычными ссы...
theGrass
24 уровень
Саратов

Отличия между слабыми, мягкими, фантомными и обычными ссылками в Java

Статья из группы Архив info.javarush
«Слабые» ссылки и «мягкие» ссылки (WeakReference, SoftReference) были добавлены в Java API давно, но не каждый программист знаком с ними. Это свидетельствует о пробеле в понимании где и как их использовать. Ссылочные классы особенно важны в контексте сборки мусора . Как все мы знаем сборщик мусора сам освобождает память занимаемую объектами, но не все программисты знают что решение об освобождении памяти он принимает исходя из типа имеющихся на объект ссылок. Отличия между слабыми, мягкими, фантомными и обычными ссылками в Java - 1Главное отличие SoftReference от WeakReference в том как сборщик с ними будет работать. Он может удалить объект в любой момент если на него указывают только weak ссылки, с другой стороны объекты с soft ссылкой будут собраны только когда JVM очень нужна память. Благодаря таким особенностям ссылочных классов каждый из них имеет свое применение. SoftReference можно использовать для реализации кэшей и когда JVM понадобится память она освободит ее за счет удаления таких объектов. А WeakReference отлично подойдут для хранения метаданных, например для хранения ссылки на ClassLoader. Если нет классов для загрузки то нет смысла хранить ссылку на ClassLoader, слабая ссылка делает ClassLoader доступным для удаления как только мы назначим ее вместо крепкой ссылки (Strong reference). В этой статье мы рассмотрим отличия типов ссылок в том числе Strong reference и Phantom reference (фантомная ссылка).

WeakReference vs SoftReference в Java

Для тех кто не знает есть 4 вида ссылок:
  1. Strong reference
  2. Weak Reference
  3. Soft Reference
  4. Phantom Reference
Strong ссылка самая простая, так как мы используем ее в программировании изо дня в день, например в коде вида String s = “abc” переменная s это и есть strong ссылка. Любой объект что имеет strong ссылку запрещен для удаления сборщиком мусора. Разумеется что это объекты которые нужны Java программе. Слабые ссылки представлены классом java.lang.ref.WeakReference, вы можете определить слабую ссылку так:

Counter counter = new Counter(); // strong reference
WeakReference weakCounter = new WeakReference(counter); //weak reference
counter = null; // now Counter object is eligible for garbage collection
Теперь, как только вы присвоили strong ссылке counter значение null (counter = null), тот объект что создан в первой строке становится доступным для удаления сборщиком мусора, потому что он больше не имеет strong ссылки. Cозданная Weak ссылка weakCounter не может предотвратить удаление сборщиком объекта Counter. С другой стороны если бы это была Soft ссылка, объект типа Counter не был бы удален до тех пор пока JVM не нуждалась бы в памяти особенно сильно. Soft ссылки в Java представлены классом java.lang.ref.SoftReference. Пример создания SoftReference в Java

Counter prime = new Counter();  // prime holds a strong reference 
SoftReference soft = new SoftReference(prime) ; //soft reference variable has SoftReference to Counter Object
prime = null;  // now Counter object is eligible for garbage collection but only be collected when JVM absolutely needs memory
После обнуления strong ссылки (в 3-ей строке) на объект Counter останется только 1 мягкая ссылка которая не сможет предотвратить удаление этого объекта сборщиком мусора, но в отличие от weak ссылки сможет отложить этот процесс до тех пор пока не появится острая нехватка памяти. Учитывая это отличие soft ссылки от weak, первая больше подходит для кэшей, а weak для метаданных. Хорошим примером служит класс WeakHashMap который является наследником интерфейса Map как и классы HashMap или TreeMap, но с одной отличительной особенностью. WeakHashMap оборачивает ключи как weak ссылки, что означает что как только не осталось strong ссылок на объект, weak ссылки которые расположены внутри WeakHashMap не спасут от сборщика мусора. Фантомные ссылки - третий тип ссылок, доступных в пакете java.lang.ref. Phantom ссылки представлены классом java.lang.ref.PhantomReference. Объект на который указывают только phantom ссылки может быть удален сборщиком в любой момент. Phantom ссылка создается точно так же как weak или soft.

DigitalCounter digit = new DigitalCounter(); // digit reference variable has strong reference
PhantomReference phantom = new PhantomReference(digit); // phantom reference
digit = null;
Как только вы обнулите strong ссылки на объект DigitalCounter, сборщик мусора удалит его в любой момент, так как теперь на него ведут только phantom ссылки. Кроме классов WeakReference, SoftReference, PhantomReference, WeakHashMap, полезно знать о классе ReferenceQueue. Вы можете воспользоваться этим классом при создании объекта класса WeakReference, SoftReference или PhantomReference:

ReferenceQueue refQueue = new ReferenceQueue(); //reference will be stored in this queue for cleanup
DigitalCounter digit = new DigitalCounter();
PhantomReference phantom = new PhantomReference(digit, refQueue);
Ссылка на объект будет добавлена в ReferenceQueue и вы сможете контролировать состояние ссылок путем опроса ReferenceQueue. Жизненный цикл Object хорошо представлен на этой диаграмме: Отличия между слабыми, мягкими, фантомными и обычными ссылками в Java - 2Вот и все отличия между weak и soft ссылками в Java. Так же мы познакомились с phantom ссылками, классом WeakHashMap и ReferenceQueue. Правильное использование ссылок поможет при сборке мусора и в результате мы получим более гибкое управление памятью в Java. Оригинал статьи
Комментарии (9)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
27 октября 2021
а зачем тогда фантом ссылка нужна, если бесполезна? Как раз о применении фантом ссылки тут не написано
Mikhail Egorov Уровень 10
7 декабря 2020
Не очень статья даже в оригинале на английском, ничего не понятно уже там. Лучше почитать вот это на хабре
Александр Уровень 1
12 декабря 2019
Первый пример кода, описывающий PhantomReference, содержит ошибку :

PhantomReference phantom = new PhantomReference(digit); // phantom reference
У класса PhantomReference существует только один конструктор с двумя аргументами: PhantomReference(T referent, ReferenceQueue<? super T> q), что является его отличием от классов SoftReference и WeakReference и обусловлено логикой его применения, которая в статье не отражена.
Javaprogrammer Уровень 22
29 января 2016
Статья затронула интересную тему, но как по мне так ее и не раскрыла. Я например так и не понял в чем разница межде ссылками Phantom и Weak? Также не понятно зачем собственно ссылки Phantom и Weak, если они никак не влияют на работу GC? Зачем их вообще использовать?
andreytemn Уровень 40
28 августа 2015
Что-то я не понял различий между weak и phantom. Они просто не дают GC убивать объекты? Проясните, пожалуйста.
tempys Уровень 31
30 июня 2015
+1
maks1m Уровень 25
29 июня 2015
Спасибо, познавательно, не знал :)
Но остался вопрос в чем главное отличие weak от phantom?
В обоих случаях GC сразу удалит объект если на него будут ссылаться только эти виды ссылок.
Пойду гуглить.