В Java существует 4 типа ссылок: StrongReference, SoftReference, WeakReference и PhantomReference (легендарная ссылка-призрак, ха-ха).
Эти четыре типа ссылок тесно связаны с GC. Давайте рассмотрим их определения и сценарии использования один за другим:
1. Сильная ссылка
StrongReference — это эталонная реализация Java по умолчанию. Она будет сохраняться в JVM как можно дольше. Если ни один объект не указывает на нее, она будет переработана после выполнения GC.
Java-код
Скопируйте код кода следующим образом:
@Тест
общественный недействительный StrongReference () {
Референт объекта = новый объект();
/**
* Создание StrongReference посредством присваивания.
*/
Объект StrongReference = референт;
AssertSame (референт, StrongReference);
референт = ноль;
Система.gc();
/**
* StrongReference не будет перерабатываться после GC.
*/
AssertNotNull (strongReference);
}
2. WeakReference и WeakHashMap
WeakReference, как следует из названия, является слабой ссылкой. Когда объект, на который ссылаются, больше не имеет сильной ссылки в JVM, слабая ссылка будет автоматически переработана после GC.
Скопируйте код кода следующим образом:
@Тест
общественный недействительный слабыйReference () {
Референт объекта = новый объект();
WeakReference<Object> слабыйRerference = новый WeakReference<Object>(ссылка);
AssertSame(referent, WeakRerference.get());
референт = ноль;
Система.gc();
/**
* Если нет сильной ссылки, указывающей на референт, слабая ссылка будет автоматически переработана после GC.
*/
AssertNull(weakRerference.get());
}
WeakHashMap использует WeakReference в качестве ключа. Если на ключ нет строгой ссылки, WeakHashMap автоматически удалит соответствующую запись после GC.
Скопируйте код кода следующим образом:
@Тест
public void слабыйHashMap() выдает InterruptedException {
Map<Object, Object> слабыйHashMap = новый WeakHashMap<Object, Object>();
Ключ объекта = новый объект();
Значение объекта = новый объект();
слабыйHashMap.put(ключ, значение);
AssertTrue(weakHashMap.containsValue(значение));
ключ = ноль;
Система.gc();
/**
* Подождите, пока недействительные записи попадут в ReferenceQueue, чтобы их можно было очистить при следующем вызове getTable.
*/
Thread.sleep(1000);
/**
* Если нет строгой ссылки на ключ, WeakHashMap автоматически удалит соответствующую запись после GC.
*/
AssertFalse(weakHashMap.containsValue(значение));
}
3.Мягкая ссылка
SoftReference имеет в основном те же характеристики, что и WeakReference. Самая большая разница заключается в том, что SoftReference будет сохранять ссылку как можно дольше, пока JVM не исчерпает память, прежде чем она будет перезагружена (гарантия виртуальной машины делает SoftReference очень подходящим для кэширования приложений).
Скопируйте код кода следующим образом:
@Тест
общественный недействительный softReference () {
Референт объекта = новый объект();
SoftReference<Object> softRerference = новый SoftReference<Object>(ссылка);
AssertNotNull(softRerference.get());
референт = ноль;
Система.gc();
/**
* мягкие ссылки будут переработаны только перед jvm OutOfMemory, поэтому они очень подходят для кэширующих приложений.
*/
AssertNotNull(softRerference.get());
}
4. Фантомная ссылка
Как главный герой этой статьи, Phantom Reference сильно отличается от WeakReference и SoftReference, поскольку его метод get() всегда возвращает значение null, отсюда и его название.
Java-код
Скопируйте код кода следующим образом:
@Тест
общественный недействительный phantomReferenceAlwaysNull () {
Референт объекта = новый объект();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(ссылка, новый ReferenceQueue<Object>());
/**
* Метод get фантомной ссылки всегда возвращает ноль.
*/
AssertNull(phantomReference.get());
}
Вы можете спросить, а какой смысл в ссылке, которая всегда возвращает null? Обратите внимание на второй параметр ReferenceQueue при построении PhantomReference (на самом деле, WeakReference и SoftReference тоже могут иметь этот параметр).
Единственное использование PhantomReference — отслеживание того, когда референт ставится в очередь в ReferenceQueue.
5. Очередь релевантности
Когда WeakReference начинает возвращать значение null, объект, на который он указывает, готов к переработке. В это время можно выполнить соответствующую работу по очистке. Передайте ReferenceQueue конструктору ссылки. Когда объект перезапускается, виртуальная машина. будет автоматически. Объект вставляется в ReferenceQueue. WeakHashMap использует ReferenceQueue для очистки записей, ключи которых больше не имеют строгих ссылок.
Java-код
Скопируйте код кода следующим образом:
@Тест
public void referenceQueue() выдает InterruptedException {
Референт объекта = новый объект();
ReferenceQueue<Object> referenceQueue = новый ReferenceQueue<Object>();
WeakReference<Object> слабаяReference = новый WeakReference<Object>(ссылка, referenceQueue);
AssertFalse(weakReference.isEnqueued());
Reference<? расширяет Object> polled = referenceQueue.poll();
AssertNull (опрошено);
референт = ноль;
Система.gc();
AssertTrue(weakReference.isEnqueued());
Reference<? расширяет объект> удален = referenceQueue.remove();
AssertNotNull (удалено);
}
6. PhantomReference против WeakReference
У PhantomReference есть два преимущества. Во-первых, он позволяет нам точно знать, когда объект удаляется из памяти. Эту функцию можно использовать для некоторых особых нужд (например, Distributed GC, XWork и google-guice также используют PhantomReference. Проделали некоторую работу по очистке).
Во-вторых, это позволяет избежать некоторых фундаментальных проблем, вызванных финализацией. Как упоминалось выше, единственная функция PhantomReference — отслеживать, когда референт помещается в очередь ReferenceQueue, но WeakReference также имеет соответствующие функции. В чем разница между ними?
Речь идет о методе финализации объекта. Этот метод будет вызываться до выполнения gc. Если объект перегружает метод финализации и намеренно создает сильную ссылку на себя внутри метода, это приведет к невозможности выполнения этого раунда GC. recycled. Этот объект может вызвать любой сбор мусора. Конечный результат заключается в том, что в JVM много мусора, но OutOfMemory. Использование PhantomReference может избежать этой проблемы, поскольку PhantomReference перезапускается после выполнения метода Finalize, что означает, что это не так. на данный момент больше не доступен. Возможно, если мы получим исходную ссылку, описанная выше проблема не возникнет. Конечно, это очень крайний пример и обычно не возникает.
7. Сравнение
Мягкие, слабые и фантомные ссылки | ||||
---|---|---|---|---|
Тип | Цель | Использовать | Когда сдается GC | Реализация класса |
Сильная ссылка | Обычная ссылка Сохраняет объекты активными, пока на них есть ссылка. | нормальная ссылка. | Любой объект, на который не указан, можно вернуть. | по умолчанию |
Мягкая ссылка | Сохраняет объекты живыми, если имеется достаточно памяти. | чтобы сохранять объекты живыми даже после того, как клиенты удалили свои ссылки (кеши, чувствительные к памяти), на случай, если клиенты снова начнут запрашивать их по ключу. | После первого прохода сборщика мусора JVM решает, что ей все еще необходимо освободить больше места. | java.lang.ref.SoftReference |
Слабая ссылка | Сохраняет объекты активными только до тех пор, пока они используются (доступны) клиентами. | Контейнеры, которые автоматически удаляют объекты, больше не используются. | После того, как gc определит, что объект слабо достижим. | java.lang.ref.WeakReference java.util.WeakHashMap |
Фантомная ссылка | Позволяет выполнить очистку после финализации, но до того, как пространство будет освобождено (заменяет или дополняет использование offfinalize()). | Специальная очистительная обработка | После доработки. | java.lang.ref.PhantomReference |
8. Резюме
Общие приложения не будут включать в себя эталонное программирование, но понимание этих знаний будет полезно для понимания принципа работы GC и настройки производительности. Их также можно использовать при реализации некоторых основных функций, таких как кэширование. Я надеюсь, что эта статья может оказаться полезной.