Когда следует удалять содержимое hashmap, чтобы избежать снижения производительности? - PullRequest
2 голосов
/ 11 марта 2010

Я работаю на Java с большой (миллионами) хэш-картой, которая на самом деле построена с емкостью 10.000.000 и коэффициентом загрузки 0,75, и она используется для кэширования некоторых значений

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

Например, с емкостью 10 миллионов и 0,75 я должен опустошить его, когда он достигнет 7,5 миллионов элементов? Потому что я пробовал различные пороговые значения, но хотел бы иметь аналитическое значение.

Я уже проверял тот факт, что очистка его, когда он полностью заполнен, повышает производительность (первые 2-3 итерации алгоритма после очистки просто заполняют его обратно, затем он начинает работать быстрее, чем до очистки)

РЕДАКТИРОВАТЬ: ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

Хэш-карта имеет длинные ключи и значения с плавающей запятой. Он содержит кешированную корреляцию содержимого, поскольку это точечный продукт векторов тегов, который я хотел кэшировать (для повышения производительности).

Итак, в основном я вычисляю ключ long, используя хэш-коды 2 содержимого:

static private long computeKey(Object o1, Object o2)
{
    int h1 = o1.hashCode();
    int h2 = o2.hashCode();

    if (h1 < h2)
    {
        int swap = h1;
        h1 = h2;
        h2 = swap;
    }

    return ((long)h1) << 32 | h2;
}

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

Использование WeakHashMap приведет к непредсказуемому уничтожению данных, даже если они все еще необходимы. Я не могу их контролировать.

Спасибо

Ответы [ 3 ]

5 голосов
/ 11 марта 2010

Почему бы не использовать LRU Cache? Из документации Java по LinkedHashMap:

Специальный конструктор предоставляется создать связанную хэш-карту, порядок которой итерации - это порядок, в котором ее записи, к которым последний раз обращались, из наименее недавно доступ к совсем недавно (доступ-порядок). это вид карты хорошо подходит для строительства LRU кеширует. Вызов пут или получить метод приводит к доступу к соответствующая запись (при условии, что это существует после вызова завершается). Метод putAll генерирует одну запись доступа для каждого отображение на указанной карте, в заказать, что сопоставления ключ-значение обеспечивается указанным элементом карты установить итератор. Других методов нет генерировать входы. В в частности, операции на представления коллекции не влияют на порядок итерации карты поддержки.

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

См. Документацию по removeEldestEntry, чтобы сделать это автоматически.

Вот код, который демонстрирует:

 public static void main(String[] args) {
    class CacheMap extends LinkedHashMap{
      private int maxCapacity;
      public CacheMap(int initialCapacity, int maxCapacity) {
        super(initialCapacity, 0.75f, true);
        this.maxCapacity = maxCapacity;
      }

      @Override
      protected boolean removeEldestEntry(Map.Entry eldest) {
        return size()>maxCapacity;
      }
    }

    int[] popular = {1,2,3,4,5};
    CacheMap myCache = new CacheMap(5, 10);
    for (int i=0; i<100; i++){
      myCache.put(i,i);
      for (int p : popular) {
        myCache.get(p);
      }
    }

    System.out.println(myCache.toString()); 
    //{95=95, 96=96, 97=97, 98=98, 99=99, 1=1, 2=2, 3=3, 4=4, 5=5}
  }
2 голосов
/ 11 марта 2010

Возможно, вы захотите использовать Google Collections ' MapMaker , чтобы создать карту с мягкими ссылками и определенным временем ожидания.

Мягкие ссылки "очищаются по усмотрению сборщика мусора в ответ на запрос памяти."

Пример:

ConcurrentMap<Long, ValueTypeHere> cacheMap = new MapMaker()
    .concurrencyLevel(32)
    .softValues()
    .expiration(30, TimeUnit.MINUTES)
    .makeMap();

Вы также можете указать слабые клавиши, если хотите, чтобы их ключи действовали подобно клавишам в WeakHashMap.

2 голосов
/ 11 марта 2010

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

Эта статья содержит больше полезной информации.

...