Когда я был в 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
Псевдоним Ясин, программист с глубиной, отношением и теплотой. Делитесь техниками программирования и жизнью вне работы, если вам нравятся мои статьи, вы можете легко"обрати внимание на"Проверьте общедоступный номер, вы также можете"Вперед"Поделись с друзьями~
Ответьте на «интервью» или «исследование» в официальном аккаунте, чтобы получить соответствующие ресурсы~