Ръководство за WeakHashMap в Java

1. Общ преглед

В тази статия ще разгледаме WeakHashMap от пакета java.util .

За да разберем структурата на данните, ще я използваме тук, за да пуснем проста кеш реализация. Имайте предвид обаче, че това има за цел да разбере как работи картата и създаването на собствена реализация на кеша е почти винаги лоша идея.

Най-просто казано, WeakHashMap е базирана на хеш-таблица реализация на интерфейса Map , с ключове, които са от тип WeakReference .

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

2. Силни, меки и слаби референции

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

2.1. Силни референции

Силната референция е най-често срещаният тип Справочник , който използваме в ежедневното си програмиране:

Integer prime = 1;

Променливата prime има силна препратка към Integer обект със стойност 1. Всеки обект, който има силна препратка, сочеща към нея, не отговаря на условията за GC.

2.2. Меки справки

Най-просто казано, обект, който има сочещ SoftReference , няма да бъде събран боклук, докато JVM абсолютно не се нуждае от памет.

Нека да видим как можем да създадем SoftReference в Java:

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

Най -председател обекта има силна референтна посочване към него.

След това обгръщаме основната силна препратка в мека препратка. След като направи тази силна референтна нула , основният обект отговаря на условията за GC, но ще бъде събран само когато JVM абсолютно се нуждае от памет.

2.3. Слаби референции

Обектите, които се препращат само със слаби препратки, се събират с нетърпение; в този случай GC няма да изчака, докато се нуждае от памет.

Можем да създадем WeakReference в Java по следния начин:

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

Когато направихме основен референтен нула , за председател обектът ще бъде боклук събрани в следващия цикъл GC, тъй като няма друг силен справка сочи към него.

Препратките от тип WeakReference се използват като ключове в WeakHashMap .

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 например, който ще съхранява нашите BigImage обекти. Ние се постави BigImage обект като ценност и imageName референтен обект като ключов. Името на изображението ще се съхранява в карта като тип WeakReference .

След това задаваме референцията imageName да бъде нула , следователно няма повече препратки, сочещи към обекта bigImage . Поведението по подразбиране на WeakHashMap е да възстанови запис, който няма препратка към него в следващия GC, така че този запис ще бъде изтрит от паметта при следващия GC процес.

Ние се нарече System.gc () да принуди JVM да задейства процес на GC. След цикъла на GC, нашата WeakHashMap ще бъде празна:

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));

Имайте предвид, че само препратката imageNameFirst е настроена на нула . В imageNameSecond позоваването остава непроменена. След задействане на GC, картата ще съдържа само един запис - imageNameSecond .

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

В тази статия разгледахме типовете препратки в Java, за да разберем напълно как java.util. WeakHashMap работи. Създадохме прост кеш, който използва поведението на WeakHashMap и тестваме дали работи както сме очаквали.

Внедряването на всички тези примери и кодови фрагменти може да се намери в проекта GitHub - който е проект на Maven, така че трябва да е лесно да се импортира и да се изпълнява както е.