Уточните четыре ссылки на Java за один раз!

Java

Когда я был в CodeReview несколько дней назад, я увиделWeakHashMapкод, а потом говорить оWeakReference, а затем поговорим о четырех ссылочных типах в Java.

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

Я спустился и снова прочитал статьи в этой области, и сегодня я сделал их ясными.

Разница между четырьмя цитатами

На самом деле разница между четырьмя ссылками заключается в том, что они по-разному обрабатываются во время сборки мусора. Подводя итог в одном предложении, если объект GC Root доступен, сильные ссылки не будут переработаны, мягкие ссылки будут переработаны при нехватке памяти, а слабые ссылки будут переработаны при первом сборщике мусора этого объекта.

Если корень GC недоступен, независимо от ссылки, он будет переработан.

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

Ниже приведена комбинация случаев, чтобы рассказать о производительности четырех ссылок перед лицом GC и их обычном использовании. Сначала установите параметры JVM:

-Xms20M -Xmx20M -Xmn10M -verbose:gc -XX:+PrintGCDetails

сильная цитата

Это ссылка, которую мы используем чаще всего. Пока корень GC этого объекта доступен во время GC, он не будет переработан. Если памяти JVM недостаточно, сразу выбрасывается OOM. Например, следующий код выдастOutOfMemoryError:

public static void main(String[] args) {
    List<Object> list = new LinkedList<>();
    for (int i = 0; i < 21; i++) {
        list.add(new byte[1024 * 1024]);
    }
}

мягкая ссылка

Мягкая ссылка, когда GC, если корень GC доступен, если памяти достаточно, он не будет переработан; если памяти недостаточно, он будет переработан. Измените приведенный выше пример на мягкую ссылку, это не будет OOM:

public static void main(String[] args) {
    List<Object> list = new LinkedList<>();
    for (int i = 0; i < 21; i++) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024]);
        list.add(softReference);
    }
}

Преобразим программу и распечатаем разницу до и после GC:

public static void main(String[] args) {
    List<SoftReference<byte[]>> list = new LinkedList<>();
    for (int i = 0; i < 21; i++) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024]);
        list.add(softReference);
        System.out.println("gc前:" + softReference.get());
    }
    System.gc();
    for (SoftReference<byte[]> softReference : list) {
        System.out.println("gc后:" + softReference.get());
    }
}

Вы обнаружите, что распечатанные журналы ценны до GC, а после GC некоторые из нихnull, что означает, что они были переработаны.

И максимальная куча, которую мы установили, составляет 20 М. Если мы изменим количество циклов на 15, мы обнаружим, что напечатанный журнал не используется после GC.nullиз. но через-verbose:gc -XX:+PrintGCDetailsПо параметрам можно узнать, что JVM все же выполняет несколько GC, но поскольку памяти еще достаточно, она не перерабатывается.

public static void main(String[] args) {
    List<SoftReference<byte[]>> list = new LinkedList<>();
    for (int i = 0; i < 15; i++) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024]);
        list.add(softReference);
        System.out.println("gc前:" + softReference.get());
    }
    System.gc();
    for (SoftReference<byte[]> softReference : list) {
        System.out.println("gc后:" + softReference.get());
    }
}

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

слабая ссылка

Мягкие ссылки, пока объект является GC, будут переработаны.

Измените приведенный выше код на мягкую ссылку, вы найдете распечатанный журнал, все из которых после GCnull.

public static void main(String[] args) {
    List<WeakReference<byte[]>> list = new LinkedList<>();
    for (int i = 0; i < 15; i++) {
        WeakReference<byte[]> weakReference = new WeakReference<>(new byte[1024 * 1024]);
        list.add(weakReference);
        System.out.println("gc前:" + weakReference.get());
    }
    System.gc();
    for (WeakReference<byte[]> weakReference : list) {
        System.out.println("gc后:" + weakReference.get());
    }
}

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

мы знаем,WeakHashMapВнутри записи управляются через слабые ссылки. Его ключ является «слабым ключом», поэтому во время GC соответствующая ему пара «ключ-значение» также будет удалена из карты.

В Томкат есть одинConcurrentCache, использовалWeakHashMap, в сочетании сConcurrentHashMap, реализует потокобезопасный кеш, заинтересованные студенты могут изучить исходный код, код очень лаконичный, плюс все комментарии, всего 59 строк.

ThreadLocalстатический внутренний класс вThreadLocalMapВход внутрь представляет собойWeakReferenceунаследованный класс.

Используйте слабые ссылки, чтобыThreadLocalMapзнаниеThreadLocalНезависимо от того, вышел ли объект из строя, как только объект выходит из строя, то есть он становится мусором, тогда данные в карте, которую он контролирует, будут бесполезны, потому что внешний мир больше не может получить к ним доступ, а затем решить стереть связанные объекты значений в Карта, ссылка на объект Entry, чтобы карта всегда была как можно меньше.

фантомная ссылка

Дизайн виртуальной ссылки несколько отличается от трех вышеперечисленных ссылок, она не влияет на GC, а предназначена для получения системного уведомления, когда объект является GC.

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

Так как же NIO использует виртуальные ссылки для управления памятью?

DirectBufferПодать заявку на часть памяти непосредственно из-за пределов кучи Java.Эта часть памяти не управляется непосредственно сборщиком мусора JVM, то есть эта часть памяти не обрабатывается напрямую в алгоритме сборки мусора.Сборщик мусора этой части памяти памяти из-за того, что DirectBuffer находится в куче Java.После того, как объект проходит GC, он очищается через механизм уведомления.

Внутри DirectBuffer естьCleaner. Этот очиститель является подклассом PhantomReference. Когда объект DirectBuffer перерабатывается, он уведомляет PhantomReference. затем вызывается ReferenceHandlertryHandlePending()методpendingОбработка.Если pending не пусто, это означает, что DirectBuffer был перезапущен, и можно вызывать Cleaner.clean()Переработанный.

Код вышеуказанного метода находится вReferenceНа занятии заинтересованные студенты могут ознакомиться с исходным кодом этого метода.

Суммировать

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

Об авторе

Публичный аккаунт WeChat: составлена ​​программа

Персональный сайт: https://yasinshaw.com

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

Ответьте на «интервью» или «исследование» в официальном аккаунте, чтобы получить соответствующие ресурсы~

公众号
публика