← Назад к вопросам

Что такое WeakHashMap?

2.2 Middle🔥 101 комментариев
#JVM и управление памятью#Коллекции

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# WeakHashMap

Определение

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

Основное назначение

1. Проблема обычного HashMap

Обычный HashMap держит сильные ссылки на ключи:

Map<Integer, String> map = new HashMap<>();
Integer key = new Integer(1);
map.put(key, "value");
key = null;  // Переменная key больше не ссылается на объект

// Но HashMap ВСЕГДА держит сильную ссылку на Integer(1)!
// Объект не будет удалён сборщиком мусора
// Это может привести к утечке памяти

2. Слабые ссылки (Weak References)

WeakHashMap использует слабые ссылки, которые НЕ препятствуют сборке мусора:

Map<Integer, String> map = new WeakHashMap<>();
Integer key = new Integer(1);
map.put(key, "value");

System.out.println(map.size());  // 1

key = null;  // Переменная освобождена
System.gc(); // Сборка мусора

System.out.println(map.size());  // 0 — ключ удалён автоматически!

3. Типы ссылок в Java

Strong Reference (Сильная ссылка)
└─ Object остаётся в памяти пока есть сильная ссылка

Weak Reference (Слабая ссылка)
└─ Object может быть удалён сборщиком мусора если нет сильных ссылок

Soft Reference (Мягкая ссылка)
└─ Object удаляется только при нехватке памяти

Phantom Reference (Фантомная ссылка)
└─ Самая слабая, используется для финализации

Пример всех типов ссылок:

String str = new String("hello");           // Strong reference

WeakReference<String> weak = new WeakReference<>(str);
SoftReference<String> soft = new SoftReference<>(str);
PhantomReference<String> phantom = new PhantomReference<>(str, queue);

str = null;  // Удалили strong reference
System.gc();

// weak станет null первой
if (weak.get() == null) {
    System.out.println("Weak reference: объект удалён");
}

// soft может остаться в памяти при наличии места
if (soft.get() != null) {
    System.out.println("Soft reference: объект ещё в памяти");
}

4. Практические примеры использования WeakHashMap

Пример 1: Кэш с автоматической очисткой

public class ImageCache {
    private static final Map<String, byte[]> cache = new WeakHashMap<>();
    
    public void cacheImage(String filename, byte[] imageData) {
        cache.put(filename, imageData);
    }
    
    public byte[] getImage(String filename) {
        return cache.get(filename);
    }
    
    // Нет необходимости вручную удалять из кэша
    // Когда нет других ссылок на ключ, запись автоматически удалится
}

Пример 2: Слушатели событий (Listeners)

public class EventBus {
    private Map<Object, List<EventListener>> listeners = new WeakHashMap<>();
    
    public void subscribe(Object source, EventListener listener) {
        listeners.computeIfAbsent(source, k -> new ArrayList<>()).add(listener);
    }
    
    public void publish(Object source, Event event) {
        List<EventListener> eventListeners = listeners.get(source);
        if (eventListeners != null) {
            for (EventListener listener : eventListeners) {
                listener.onEvent(event);
            }
        }
    }
    
    // Когда source больше не используется в коде,
    // запись в listeners автоматически удалится
}

Пример 3: Кэш объектов DOM элементов

public class DOMCache {
    private Map<Element, ElementData> elementData = new WeakHashMap<>();
    
    public void setData(Element element, ElementData data) {
        elementData.put(element, data);
    }
    
    public ElementData getData(Element element) {
        return elementData.get(element);
    }
    
    // Когда DOM element удаляется со страницы,
    // данные автоматически удаляются из кэша
}

5. Сравнение HashMap и WeakHashMap

ПараметрHashMapWeakHashMap
Тип ссылокСильныеСлабые
Сборка мусораНе удаляет ключиУдаляет неиспользуемые ключи
ИспользуемостьУниверсальнаяСпециализированная
ПроизводительностьБыстрееНемного медленнее
Утечки памятиВероятны при неправильном использованииАвтоматическая очистка
ПотокобезопасностьНет (используй Collections.synchronizedMap)Нет

6. Потокобезопасность

WeakHashMap НЕ потокобезопасен, как и HashMap:

// Неправильно для многопоточности
Map<Key, Value> map = new WeakHashMap<>();

// Правильно
Map<Key, Value> map = Collections.synchronizedMap(new WeakHashMap<>());

7. Важные особенности

Непредсказуемость:

WeakHashMap<String, String> map = new WeakHashMap<>();
map.put("key", "value");

// Строки в Java интернируются, поэтому строка живёт долго
System.out.println(map.size());  // Может быть 1 или 0

// С объектами это яснее
weakMap.put(new Object(), "value");
System.out.println(weakMap.size());  // 0 (объект был удалён)

Проблема с примитивами:

// Integer с малыми значениями кэшируются
Integer key1 = 5;  // Автоматически кэшированная ссылка
Map<Integer, String> map = new WeakHashMap<>();
map.put(key1, "value");
key1 = null;
System.gc();
System.out.println(map.size());  // Может быть 1 (Integer 5 живёт в кэше)

// Integer с большими значениями
Integer key2 = 200;
map.put(key2, "value");
key2 = null;
System.gc();
System.out.println(map.size());  // 0 (удалится как ожидается)

8. Когда НЕ использовать WeakHashMap

// Неправильно — строки интернируются в Java
Map<String, String> cache = new WeakHashMap<>();

// Неправильно — Integer кэшируются для значений -128..127
Map<Integer, String> cache = new WeakHashMap<>();

// Правильно — пользовательские объекты
Map<User, UserData> cache = new WeakHashMap<>();

Выводы

WeakHashMap — это специализированный инструмент для:

  • Кэширования с автоматической очисткой
  • Хранения метаданных, связанных с объектами
  • Реализации слушателей событий
  • Предотвращения утечек памяти в специфических сценариях

Однако его нужно использовать с осторожностью, так как поведение непредсказуемо с интернированными строками и кэшированными числами. В современных приложениях часто лучше использовать явное управление кэшем через Caffeine или Guava Cache.

Что такое WeakHashMap? | PrepBro