Рубрики
Без рубрики

Руководство по WeakHashMap на Java

Объяснение карты weakhash-как она работает, когда ее использовать, и небольшой пример.

Автор оригинала: baeldung.

1. Обзор

В этой статье мы рассмотрим WeakHashMap из пакета java.util .

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

Проще говоря, WeakHashMap представляет собой реализацию интерфейса Map на основе хэш-таблицы с ключами типа WeakReference .

Запись в WeakHashMap будет автоматически удалена, когда ее ключ больше не используется в обычном режиме, что означает, что нет ни одной Ссылки , указывающей на этот ключ. Когда процесс сборки мусора (GC) отбрасывает ключ, его запись эффективно удаляется с карты, поэтому этот класс ведет себя несколько иначе, чем другие реализации Map .

2. Сильные, мягкие и Слабые ссылки

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

2.1. Сильные Ссылки

Сильная ссылка-это наиболее распространенный тип Ссылки , который мы используем в нашем повседневном программировании:

Integer prime = 1;

Переменная prime имеет сильную ссылку на Целое число объект со значением 1. Любой объект, на который есть сильная ссылка, указывающая на него, не подходит для GC.

2.2. Мягкие ссылки

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

Давайте посмотрим, как мы можем создать SoftReference в Java:

Integer prime = 1;  
SoftReference soft = new SoftReference(prime); 
prime = null;

Объект prime имеет сильную ссылку, указывающую на него.

Затем мы превращаем prime сильную ссылку в мягкую ссылку. После создания этой надежной ссылки null объект prime имеет право на GC , но будет собран только тогда, когда JVM абсолютно необходима память.

2.3. Слабые ссылки

Объекты, на которые ссылаются только слабые ссылки, охотно собирают мусор; в этом случае GC не будет ждать, пока ему понадобится память.

Мы можем создать Слабую ссылку в Java следующим образом:

Integer prime = 1;  
WeakReference soft = new WeakReference(prime); 
prime = null;

Когда мы создали prime ссылку null , объект prime будет собран в следующем цикле GC, так как нет другой сильной ссылки, указывающей на него.

Ссылки на Слабая связь тип используются в качестве ключей в Карта weakhash .

3. WeakHashMap как эффективный кэш памяти

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

Использование простого HashMap не будет хорошим выбором, потому что объекты значений могут занимать много памяти. Более того, они никогда не будут извлечены из кэша процессом GC, даже если они больше не используются в нашем приложении.

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

К счастью, WeakHashMap обладает именно этими характеристиками. Давайте протестируем нашу WeakHashMap и посмотрим, как она себя ведет:

WeakHashMap map = new WeakHashMap<>();
BigImage bigImage = new BigImage("image_id");
UniqueImageName imageName = new UniqueImageName("name_of_big_image");

map.put(imageName, bigImage);
assertTrue(map.containsKey(imageName));

imageName = null;
System.gc();

await().atMost(10, TimeUnit.SECONDS).until(map::isEmpty);

Мы создаем экземпляр WeakHashMap , в котором будут храниться наши Большие изображения объекты. Мы помещаем Большое изображение объект в качестве значения и имя изображения ссылку на объект в качестве ключа. Имя изображения будет сохранено на карте в виде Слабой ссылки типа.

Затем мы устанавливаем ссылку imageName равной null , поэтому больше нет ссылок , указывающих на объект big Image . Поведение по умолчанию WeakHashMap состоит в том, чтобы восстановить запись, которая не имеет ссылки на нее при следующем GC, поэтому эта запись будет удалена из памяти следующим процессом GC.

Мы вызываем System.gc () , чтобы заставить JVM запустить процесс GC. После цикла GC наша Карта weakhash будет пуста:

WeakHashMap map = new WeakHashMap<>();
BigImage bigImageFirst = new BigImage("foo");
UniqueImageName imageNameFirst = new UniqueImageName("name_of_big_image");

BigImage bigImageSecond = new BigImage("foo_2");
UniqueImageName imageNameSecond = new UniqueImageName("name_of_big_image_2");

map.put(imageNameFirst, bigImageFirst);
map.put(imageNameSecond, bigImageSecond);
 
assertTrue(map.containsKey(imageNameFirst));
assertTrue(map.containsKey(imageNameSecond));

imageNameFirst = null;
System.gc();

await().atMost(10, TimeUnit.SECONDS)
  .until(() -> map.size() == 1);
await().atMost(10, TimeUnit.SECONDS)
  .until(() -> map.containsKey(imageNameSecond));

Обратите внимание, что только имя изображения Сначала ссылка имеет значение null . Второе имя изображения ссылка остается неизменной. После запуска GC карта будет содержать только одну запись – imageNameSecond .

4. Заключение

В этой статье мы рассмотрели типы ссылок в Java, чтобы полностью понять, как java.util. WeakHashMap работает. Мы создали простой кэш, который использует поведение WeakHashMap и проверяем, работает ли он так, как мы ожидали.

Реализацию всех этих примеров и фрагментов кода можно найти в проекте GitHub , который является проектом Maven, поэтому его должно быть легко импортировать и запускать как есть.