theGrass
24 уровень
Саратов

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

Статья из группы Архив info.javarush.ru
участников
«Слабые» ссылки и «мягкие» ссылки (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. Оригинал статьи
Комментарии (11)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
10 ноября 2021, 16:15
очень слабенько и ошибками написано о фантомных ссылках. Ничего не сказано об важном механизме очереди ReferenceQueue.
Евгений Дорджиев
Уровень 2, Санкт-Петербург, Россия
27 октября 2021, 17:21
а зачем тогда фантом ссылка нужна, если бесполезна? Как раз о применении фантом ссылки тут не написано
Mikhail Egorov
Уровень 10, Tomsk, Россия
7 декабря 2020, 10:03
Не очень статья даже в оригинале на английском, ничего не понятно уже там. Лучше почитать вот это на хабре
Александр
Уровень 1, Москва
12 декабря 2019, 16:29
Первый пример кода, описывающий PhantomReference, содержит ошибку :
PhantomReference phantom = new PhantomReference(digit); // phantom reference
У класса PhantomReference существует только один конструктор с двумя аргументами: PhantomReference(T referent, ReferenceQueue<? super T> q), что является его отличием от классов SoftReference и WeakReference и обусловлено логикой его применения, которая в статье не отражена.
Сергей Android Developer в ITIK
6 декабря 2020, 14:49
Спасибо большое, а то я прочитал, но так и не понял (до вашего комментария) в чем вообще различаются слабые, мягкие и фантомные ссылки
Javaprogrammer
Уровень 22, Киев, Украина
29 января 2016, 17:14
Статья затронула интересную тему, но как по мне так ее и не раскрыла. Я например так и не понял в чем разница межде ссылками Phantom и Weak? Также не понятно зачем собственно ссылки Phantom и Weak, если они никак не влияют на работу GC? Зачем их вообще использовать?
Fry
Уровень 41, Львов, Украина
29 января 2016, 17:28
в андроиде такие штуки очень часто используют, так как ресурсы не вечные, и очень ограниченные.
artechve
Уровень 17, Москва, Россия
26 апреля 2017, 14:34
статья непонятная. вот тут вроде получше samolisov.blogspot.ru/2011/09/phantomreferences-java.html
и вот тут www.javaportal.ru/java/articles/referenceclasses.html
andreytemn
Уровень 40, Россия
28 августа 2015, 11:13
Что-то я не понял различий между weak и phantom. Они просто не дают GC убивать объекты? Проясните, пожалуйста.
tempys
Уровень 31, Svyatoshino, Россия
30 июня 2015, 10:33
+1
maks1m
Уровень 25, Украина
29 июня 2015, 16:40
Спасибо, познавательно, не знал :)
Но остался вопрос в чем главное отличие weak от phantom?
В обоих случаях GC сразу удалит объект если на него будут ссылаться только эти виды ссылок.
Пойду гуглить.