Понимание сильных ссылок, мягких ссылок, слабых ссылок и виртуальных ссылок Java.

Java задняя часть

предисловие

Javaвоплощать в жизньGCопределить, является ли объектвыживатьЕсть два способа, один из которыхподсчет ссылок.

подсчет ссылок: Каждый объект в куче Java имеет атрибут счетчика ссылок, который увеличивается на 1 каждый раз, когда ссылка добавляется, и уменьшается на 1 каждый раз, когда ссылка освобождается.

существуетJDK 1.2В предыдущих версиях, если на объект не ссылалась какая-либо переменная, программа больше не могла использовать этот объект. То есть только объекты в (reachable)достижимое состояние, программа может его использовать.

отJDK 1.2Начало версии, ссылки на объекты разбиты на4различные уровни, позволяющие программе более гибко управлятьжизненный цикл объекта. Этот4уровень видаот высокого к низкомуследующим образом:сильная цитата,мягкая ссылка,слабая ссылкаифантомная ссылка.

текст

1. Сильная ссылка

сильная цитатаявляется наиболее часто используемой ссылкой. Если объект имеет сильную ссылку, тоуборщик мусораОн никогда не будет переработан. следующее:

    Object strongReference = new Object();

когдаНедостаточно памятичас,JavaВиртуальная машина предпочла бы броситьOutOfMemoryErrorошибка при создании программыАномальное завершение, и не будет полагаться на случайныеРециркулироватьимеютсильная цитатаизобъектрешить проблему нехватки памяти. Если на объект строго ссылаютсякогда не используется, необходимо ослабить, чтобыGCмогут быть переработаны следующим образом:

    strongReference = null;

установить явноstrongReferenceобъектnull, или пусть этовнеобъектжизненный циклдиапазон, тоgcдумать объектссылки не существует, то объект может быть переработан. Когда именно он будет собран, зависит отGCалгоритм.

    public void test() {
        Object strongReference = new Object();
        // 省略其他操作
    }

ввнутри методасуществует одинсильная цитата, эта ссылка хранится вJavaкуча, а фактическое цитируемое содержимое (Object)Сохранить какJavaкучасередина. когда этоМетод работает до завершения, он выйдетстек методов, эталонный объектЦитатыза0, объект будет переработан.

но если этоstrongReferenceдаглобальная переменнаяКогда объект не используется, его необходимо назначить какnull,так каксильная цитатаНе будет собираться мусор.

Очистить метод ArrayList:

существуетArrayListкласс определяетelementDataмассив при вызовеclearКогда метод очищает массив, каждому элементу массива присваивается значениеnull. отличается отelementData=null, сильная ссылка все еще существует, избегая последующих вызововadd()Память сохраняется, когда элементы добавляются другими методамиперераспределить. использовать какclear()методмассив памятиХранится втип ссылкипровестиосвобождение памятиОсобенно полезно, чтобы можно было своевременно освобождать память.

2. Мягкая ссылка

Если объект имеет толькомягкая ссылка,нодостаточно места в памятичас,уборщик мусораСразуНе будуутилизировать его; еслиНедостаточно памяти, будетРециркулироватьпамять на эти объекты. Объект может использоваться программой до тех пор, пока он не будет собран сборщиком мусора.

Мягкие ссылки могут использоваться для реализации кэшей, чувствительных к памяти.

    // 强引用
    String strongReference = new String("abc");
    // 软引用
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<String>(str);

мягкая ссылкаможет сэталонная очередь(ReferenceQueue) в комбинации. еслимягкая ссылкаСсылочный объектвывоз мусора,JAVAВиртуальная машина поставит этомягкая ссылкадобавлен в связанныйэталонная очередьсередина.

    ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);

    str = null;
    // Notify GC
    System.gc();

    System.out.println(softReference.get()); // abc

    Reference<? extends String> reference = referenceQueue.poll();
    System.out.println(reference); //null

Примечание. Мягкий эталонный объект будет утилизирован, когда памяти JVM не хватит. Мы вызываем метод System.gc() только для уведомления. Когда JVM сканирует восстановленный объект, он определяется собственным состоянием JVM. Даже если программный эталонный объект сканируется, он не обязательно будет утилизирован, он будет утилизирован только при нехватке памяти.

Когда памяти мало,JVMПервое местомягкая ссылкасерединаобъектссылка установлена ​​наnull, затем сообщитеуборщик мусораПерерабатывать:

    if(JVM内存不足) {
        // 将软引用中的对象引用置为null
        str = null;
        // 通知垃圾回收器进行回收
        System.gc();
    }

Это,поток сбора мусорабудет кинут в виртуальную машинуOutOfMemoryErrorназад передмягкий эталонный объектвиртуальная машинаУтилизация будет иметь максимально возможный приоритетдолгое время без делаизмягкий эталонный объект. темтолько что построенныйили просто б/у** "новее"Мягкие объекты будут максимально использоваться виртуальной машиной.Зарезервировано **, это введениеэталонная очередьReferenceQueueпричина.

Сценарии применения:

Кнопка «Назад» в браузере. Когда вы нажимаете назад, отображается ли содержимое веб-страницы при повторном запросе или извлечении из кэша? Это зависит от конкретной стратегии реализации.

  1. Если веб-страница повторно использует свое содержимое в конце просмотра, ее необходимо перестроить, когда вы нажимаете «Назад», чтобы просмотреть ранее просмотренную страницу;
  2. Если просматриваемые веб-страницы сохраняются в памяти, это приведет к большому расходу памяти и даже к переполнению памяти.

В настоящее время можно использовать мягкие ссылки, которые очень хорошо решают актуальную проблему:

    // 获取浏览器对象进行浏览
    Browser browser = new Browser();
    // 从后台程序加载浏览页面
    BrowserPage page = browser.getPage();
    // 将浏览完毕的页面置为软引用
    SoftReference softReference = new SoftReference(page);

    // 回退或者再次浏览此页面时
    if(softReference.get() != null) {
        // 内存充足,还没有被回收器回收,直接获取缓存
        page = softReference.get();
    } else {
        // 内存不足,软引用的对象已经回收
        page = browser.getPage();
        // 重新构建软引用
        softReference = new SoftReference(page);
    }

3. Слабая ссылка (WeakReference)

слабая ссылкаимягкая ссылкаРазница в том, что есть толькослабая ссылкаобъект владеетболее эфемерныйизжизненный цикл. В процессе сканирования нити сборщика мусора области памяти, находящейся под его юрисдикцией, однажды он находит толькослабая ссылкаобъекта, независимо от текущегоДостаточно ли памяти?, будетРециркулироватьего память. Однако, поскольку сборщик мусора являетсяпоток с низким приоритетом,следовательнонеуверенныйвстречаскорообнаружил, что толькослабая ссылкаОбъект.

    String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    str = null;

JVMПервое местомягкая ссылкасерединаобъектссылка установлена ​​наnull, затем сообщитеуборщик мусораПерерабатывать:

    str = null;
    System.gc();

Примечание. Если объект используется время от времени (редко), и вы хотите иметь возможность получать его всякий раз, когда вы его используете, но не хотите влиять на сборку мусора этого объекта, вам следует использовать слабую ссылку, чтобы запомнить это. объект.

Следующий код сделаетслабая ссылкастать одним сновасильная цитата:

    String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    // 弱引用转强引用
    String strongReference = weakReference.get();

такой же,слабая ссылкаможет сэталонная очередь(ReferenceQueue) в сочетании, еслислабая ссылкацитируетсяобъектодеяловывоз мусора,JavaВиртуальная машина поставит этослабая ссылкадобавлен в связанныйэталонная очередьсередина.

Простой тест:

GCTarget.java

public class GCTarget {
    // 对象的ID
    public String id;

    // 占用内存空间
    byte[] buffer = new byte[1024];

    public GCTarget(String id) {
        this.id = id;
    }

    protected void finalize() throws Throwable {
        // 执行垃圾回收时打印显示对象ID
        System.out.println("Finalizing GCTarget, id is : " + id);
    }
}

GCTargetWeakReference.java

public class GCTargetWeakReference extends WeakReference<GCTarget> {
    // 弱引用的ID
    public String id;

    public GCTargetWeakReference(GCTarget gcTarget,
              ReferenceQueue<? super GCTarget> queue) {
        super(gcTarget, queue);
        this.id = gcTarget.id;
    }

    protected void finalize() {
        System.out.println("Finalizing GCTargetWeakReference " + id);
    }
}

WeakReferenceTest.java

public class WeakReferenceTest {
    // 弱引用队列
    private final static ReferenceQueue<GCTarget> REFERENCE_QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        LinkedList<GCTargetWeakReference> gcTargetList = new LinkedList<>();

        // 创建弱引用的对象,依次加入链表中
        for (int i = 0; i < 5; i++) {
            GCTarget gcTarget = new GCTarget(String.valueOf(i));
            GCTargetWeakReference weakReference = new GCTargetWeakReference(gcTarget,
                REFERENCE_QUEUE);
            gcTargetList.add(weakReference);

            System.out.println("Just created GCTargetWeakReference obj: " +
                gcTargetList.getLast());
        }

        // 通知GC进行垃圾回收
        System.gc();

        try {
            // 休息几分钟,等待上面的垃圾回收线程运行完成
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 检查关联的引用队列是否为空
        Reference<? extends GCTarget> reference;
        while((reference = REFERENCE_QUEUE.poll()) != null) {
            if(reference instanceof GCTargetWeakReference) {
                System.out.println("In queue, id is: " +
                    ((GCTargetWeakReference) (reference)).id);
            }
        }
    }
}

бегатьWeakReferenceTest.java, Результаты приведены ниже:

видимыйWeakReferenceЖизненный цикл объекта в основном определяетсяуборщик мусорарешение, как только поток сборки мусора находитСлабый эталонный объект,в следующий разGCВ процессе он будет переработан.

4. Фантомная ссылка

фантомная ссылкаКак следует из названия, этотолько по названию. В отличие от нескольких других ссылок,фантомная ссылкаиНе будурешить объектжизненный цикл. если объектсодержит только фантомные ссылки, то это то же самое, чтонет цитатТочно так же он может быть собран сборщиком мусора в любое время.

Сценарии применения:

фантомная ссылкав основном используетсяотслеживать объектсборщиком мусораРециркулироватьМероприятия.фантомная ссылкаимягкая ссылкаислабая ссылкаОдно отличие в том, что:

Виртуальная ссылка должна использоваться вместе с очередью ссылок (ReferenceQueue). Когда сборщик мусора готов освободить объект, если он обнаружит, что у него все еще есть виртуальная ссылка, он добавит виртуальную ссылку в связанную с ним очередь ссылок перед освобождением памяти объекта.

    String str = new String("abc");
    ReferenceQueue queue = new ReferenceQueue();
    // 创建虚引用,要求必须与一个引用队列关联
    PhantomReference pr = new PhantomReference(str, queue);

На программы можно ссылаться, судяочередьприсоединилсяфантомная ссылка, чтобы узнать, будет ли указанный объектвывоз мусора. Если программа обнаружит, что в очередь ссылок добавлена ​​виртуальная ссылка, она можетдо восстановления памятиПримите необходимые меры.

Суммировать

Уровни и сильные стороны четырех ссылок в Java от высокого к низкому: сильная ссылка -> мягкая ссылка -> слабая ссылка -> виртуальная ссылка

когдауборщик мусораПри переработке некоторые объекты перерабатываются, а некоторые нет. Сборщик мусора будеткорневой объектObjectПриходитьотметкаВыжившие объекты, а затем некоторые недоступные объекты и некоторые объекты, на которые есть ссылки, перерабатываются.

Объясните с помощью формы следующим образом:

тип ссылки Время сбора мусора использовать время выживания
сильная цитата никогда общее состояние объекта Завершить, когда JVM перестанет работать
мягкая ссылка Когда памяти мало кеш объектов Завершить, когда не хватает памяти
слабая ссылка При обычной сборке мусора кеш объектов Завершить после сборки мусора
фантомная ссылка При обычной сборке мусора Сборка мусора отслеживаемых объектов Завершить после сборки мусора

Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack

image

Эта учетная запись будет продолжать делиться сухими товарами серверных технологий, включая основы виртуальных машин, многопоточное программирование, высокопроизводительные фреймворки, асинхронное ПО, промежуточное ПО для кэширования и обмена сообщениями, распределенные и микросервисы, материалы для обучения архитектуре и расширенные учебные материалы и статьи.