Мусорные ссылки в Java
Есть StrongReference — это самые обычные ссылки, которые мы создаем каждый день.
Object object = new Object();//создал обьект object = null;//теперь может быть собран сборщиком мусора
И есть три “особых” типа ссылок — SoftReference, WeakReference, PhantomReference. По сути, различие между всеми типами ссылок только одно — поведение GC с объектами, на которые они ссылаются. Мы более детально обсудим особенности каждого типа ссылок позже, а пока достаточно будет следующих знаний:
- SoftReference — мягкая ссылка, если GC видит, что объект доступен только через цепочку soft-ссылок, то он удалит его из памяти. Наверное.
- WeakReference – слабая ссылка , если GC видит, что объект доступен только через цепочку weak-ссылок, то он удалит его из памяти.
- PhantomReference — фантомная ссылка, если GC видит, что объект доступен только через цепочку phantom-ссылок, то он его удалит из памяти. После нескольких запусков GC.
Также можно сказать, что у типов ссылок есть некая степень мягкости:
- Обычная жесткая ссылка – любая переменная ссылочного типа. Очистится сборщиком мусора не раньше, чем станет неиспользуемой.
- SoftReference. Объект не станет причиной израсходования всей памяти – гарантированно будет удален до возникновения OutOfMemoryError. Может быть раньше, зависит от реализации сборщика мусора.
- WeakReference. Слабее мягкой. Не препятствует утилизации объекта, сборщик мусора игнорирует такие ссылки.
- PhantomReference. Используется для “предсмертной” обработки объекта: объект доступен после финализации, пока не очищен сборщиком мусора.
Если пока не понятно, в чем же разница, то не переживайте, скоро все станет на свои места. Мелочи в деталях, а детали будут дальше.
8.2 WeakReference и SoftReference в Java
Для начала давайте рассмотрим разницу между WeakReference и SoftReference в Java.
Если вкратце, то сборщик мусора освободит память объекта, если на него указывают только слабые ссылки. Если на объект указывают ссылки SoftReferences, то освобождение памяти происходит, когда JVM сильно нуждается в памяти.
Это дает определенное преимущество SoftReference перед Strong ссылкой в определенных случаях. Например, SoftReference используют для реализации кэша приложений, поэтому JVM первым делом удалит объекты, на которые указывают только SoftReferences.
WeakReference отлично подходит для хранения метаданных, например, для хранения ссылки на ClassLoader. Если ни один класс не загружен, то не стоит ссылаться на ClassLoader. Именно поэтому WeakReference делает возможность сборщику мусора выполнить свою работу с ClassLoader, как только на него удалится последняя сильная ссылка.
Пример WeakReference в Java:
// какой-то объект Student student = new Student(); // слабая ссылка на него WeakReference weakStudent = new WeakReference(student); // теперь объект Student может быть собран сборщиком мусора student = null;
Пример SoftReference в Java:
// какой-то объект Student student = new Student(); // слабая ссылка на него SoftReference softStudent = new SoftReference(student) // теперь объект Student может быть собран сборщиком мусора // но это случится только в случае сильной необходимости JVM в памяти student = null;
8.3 Ссылка PhantomReference в Java
Экземпляр PhantomReference создается точно также, как и на примерах WeakReference и SoftReference, но используется он довольно редко.
PhantomReference может быть собрана сборщиком мусора, если на объект нет сильных (Strong), слабых ссылок (WeakReference) или мягких (SoftReference).
Вы можете создать объект Phantom Reference следующим образом:
PhantomReference myObjectRef = new PhantomReference(MyObject);
PhantomReference может использоваться в ситуациях, когда использование finalize() не имеет смысла. Этот ссылочный тип отличается от других типов, поскольку он не предназначен для доступа к объекту. Он является сигналом о том, что объект уже финализирован и сборщик мусора готов вернуть свою память.
Для этого сборщик мусора помещает его в специальный ReferenceQueue для последующей обработки. ReferenceQueue — это место, куда помещаются ссылки на объекты для освобождение памяти.
Фантомные ссылки — это безопасный способ узнать, что объект удален из памяти. Например, рассмотрим приложение, которое имеет дело с большими изображениями. Предположим, что мы хотим загрузить изображение в память, когда оно уже находится в памяти, которая готова для сборки мусора. В этом случае мы хотим подождать пока сборщик мусора убьет старое изображение и только потом загружать в память новое.
Здесь PhantomReference является гибким и безопасным выбором. Ссылка на старое изображение будет передана в ReferenceQueue после уничтожения старого объекта изображения. Получив эту ссылку, мы можем загрузить новое изображение в память.
Отличия между слабыми, мягкими, фантомными и обычными ссылками в 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
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 хорошо представлен на этой диаграмме: Вот и все отличия между weak и soft ссылками в Java. Так же мы познакомились с phantom ссылками, классом WeakHashMap и ReferenceQueue. Правильное использование ссылок поможет при сборке мусора и в результате мы получим более гибкое управление памятью в Java. Оригинал статьи