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

    «Слабые» ссылки и «мягкие» ссылки (WeakReference, SoftReference) были добавлены в Java API давно, но не каждый программист знаком с ними. Это свидетельствует о пробеле в понимании где и как их использовать. Ссылочные классы особенно важны в контексте сборки мусора . Как все мы знаем сборщик мусора сам освобождает память занимаемую объектами, но не все программисты знают что решение об освобождении памяти он принимает исходя из типа имеющихся на объект ссылок.
    Главное отличие 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<Counter> weakCounter = new WeakReference<Counter>(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<Counter> soft = new SoftReference<Counter>(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<DigitalCounter> phantom = new PhantomReference<DigitalCounter>(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<DigitalCounter> phantom = new PhantomReference<DigitalCounter>(digit, refQueue);

    Ссылка на объект будет добавлена в ReferenceQueue и вы сможете контролировать состояние ссылок путем опроса ReferenceQueue. Жизненный цикл Object хорошо представлен на этой диаграмме:



    Вот и все отличия между weak и soft ссылками в Java. Так же мы познакомились с phantom ссылками, классом WeakHashMap и ReferenceQueue. Правильное использование ссылок поможет при сборке мусора и в результате мы получим более гибкое управление памятью в Java.

    Оригинал статьи

6 комментариев

maks1m
Спасибо, познавательно, не знал :)
Но остался вопрос в чем главное отличие weak от phantom?
В обоих случаях GC сразу удалит объект если на него будут ссылаться только эти виды ссылок.
Пойду гуглить.
tempys
+1
andreytemn
Что-то я не понял различий между weak и phantom. Они просто не дают GC убивать объекты? Проясните, пожалуйста.
Javaprogrammer
  • Javaprogrammer
  • 0
  • Комментарий отредактирован 2016-01-29 17:14:23 пользователем Javaprogrammer
Статья затронула интересную тему, но как по мне так ее и не раскрыла. Я например так и не понял в чем разница межде ссылками Phantom и Weak? Также не понятно зачем собственно ссылки Phantom и Weak, если они никак не влияют на работу GC? Зачем их вообще использовать?
Fry
в андроиде такие штуки очень часто используют, так как ресурсы не вечные, и очень ограниченные.
artechve
статья непонятная.

вот тут вроде получше
samolisov.blogspot.ru/2011/09/phantomreferences-java.html
и вот тут
www.javaportal.ru/java/articles/referenceclasses.html
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.