2013-05-02 3 views
1

Я сталкиваюсь с некоторыми проблемами с памятью с моим проектом, поэтому я решил подчеркнуть некоторые порции, чтобы увидеть некоторые измерения производительности. Я использую библиотеку ConcurrentLinkedHashMap Google в качестве кеша LRU. Соответствующие части моего кода тестирования приведены ниже:Усилие для очистки памяти

final ConcurrentLinkedHashMap cache = new ConcurrentLinkedHashMap.Builder<Long,Long>() 
      .maximumWeightedCapacity(200000) 
      .build(); 

for (int i = 0; i < 10; i++) { 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      int count = 0; 
      while (count < 1000000) { 
       if (throttle) { 
        Thread.sleep(1000); 
        continue; 
       } 
       cache.put(random.nextLong(), random.nextLong()); 
       count++; 
      } 
     } 
    }).start(); 
} 

this.wait(); 

Я установил throttle флаг true когда память попадет более 50%. У меня есть контрольная нить, которая измеряет каждые 2 секунд. Вот цифры, которые я получил:

Size: 423902 Weighted Size: 200001 Memory: 0.11229571913729916 
Size: 910783 Weighted Size: 200001 Memory: 0.25812696264655144 
Size: 1373394 Weighted Size: 200001 Memory: 0.38996117352719034 
Size: 2120239 Weighted Size: 200001 Memory: 0.6203725762957892 
Size: 2114424 Weighted Size: 200000 Memory: 0.6233790564491212 
Size: 2114424 Weighted Size: 200000 Memory: 0.6233790564491212 
Size: 2114424 Weighted Size: 200000 Memory: 0.6233790564491212 
Size: 2114424 Weighted Size: 200000 Memory: 0.6233790564491212 
Size: 2114424 Weighted Size: 200000 Memory: 0.6233790564491212 
Size: 2114424 Weighted Size: 200000 Memory: 0.6233790564491212 

Я не видя evicted записи кэша LRU очищаемой по некоторым причинам. Я слышал, что ручное вызов System.gc() - плохая идея. Если да, то какой способ эффективно очистить память?

ON SIDE ПРИМЕЧАНИЕ: кто-нибудь знает, что делает size() за ConcurrentLinkedHashMap? weightedSize() возвращает правильное значение, но я волнуюсь, что size возвращает что-то значительно большее.

+0

как вы получаете статистику? например: Размер: 423902 Взвешенный размер: 200001 Память: 0.11229571913729916 ... – fuyou001

ответ

3

Как показывают ваши номера, кеш не гарантирует строгого максимума, но пытается сохранить этот высокий водяной знак. Если бы это сделало сильную гарантию, тогда это ограничило бы параллелизм путем блокирования вызова для каждой операции записи и не сможет эффективно поддерживать политику LRU верхнего уровня. В Guas's Cache мы делаем это ограничение с помощью блокировки, но этот компромисс имеет ограничения.

Поскольку CLHM асинхронно связывает хеш-таблицу и структуры данных LRU, эти два номера могут отклоняться. Оценка: size: ConcurrentHashMap. Это самая точная оценка пар ключ-значение в любой момент времени. weighted size рассчитывается по политике LRU, когда он повторяет операции с картами против своих структур данных для определения порядка повторения и выполнения выселений. Весовой размер остается на ожидаемом максимуме, потому что политика будет выходить, когда превышен порог.

Ожидается, что размер будет разным в пакетах, но кеш всегда будет стремиться к саморегуляции. В вашем примере поведение усугубляется, потому что операционная система будет планировать поток для большого временного фрагмента. Это позволяет выполнять гораздо больше вложений, чем это возможно в реальном сценарии. Амортизированное управление LRU означает, что выселение не может идти в ногу с момента его кражи немного времени из одного потока в любой данный момент. Чтобы лучше моделировать фактическое поведение, MemoryLeakTest заставляет контекстный переключатель между операциями.

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

+0

Благодарим вас за ввод. Я понимаю, что тест немного экстремален, и мое фактическое приложение, вероятно, будет делать только в среднем 50 вставок в секунду. Однако я не понимаю, почему, когда я «дросселирую» все потоки (когда приложение обнаружило> 50% использования памяти), JVM не использует возможность «очистить» элементы, которые выведены из карты LRU. – Jin

+0

Или, скорее, карта LRU не использует возможность реально очистить карту, поэтому 'size()' будет равен 'weightedSize()' – Jin

+0

Фактически, принимая это как ответ. Глядя на мой журнал статистики, я выполняю ~ 500 вложений в секунду. Однако добавление Thread.sleep (2) перед каждой вставкой, похоже, обеспечивает достаточное время для автоматического исправления кеша. Поэтому кажется, что это не проблема, которую я ищу. Спасибо! (если у вас есть ответ на мой предыдущий вопрос относительно того, почему кеш LRU в конечном итоге не очистится, сообщите мне) – Jin

0

Не является ли политика выселения по умолчанию первой в первую очередь? Если вы смотрите на первые вставки, чтобы увидеть, как их выселяют? Если вы смотрите на последнее, вы их не увидите.

Это из документации:

 
The default 
* weigher assigns each value a weight of 1 to bound the map by the 
* total number of key-value pairs. A map that holds collections may choose to 
* weigh values by the number of elements in the collection and bound the map 
* by the total number of elements that it contains. A change to a value that 
* modifies its weight requires that an update operation is performed on the 
* map. 

Так взвешенная размер не изменится по умолчанию на основе моего чтения этого.

+0

Я не, я просто предположил, что политика LRU работает, как указано. Я просто произвольно генерирую объекты 'long' для вставки. Как я могу проверить, действительно ли они выселены? Я думаю, что они выселены, поскольку счетчик «weightedSize()» отлично (200000) – Jin

+0

Но почему вы ожидаете, что взвешенный размер изменится? Как только вы ударите его, один элемент будет выселен (на основе политики) по мере добавления одного элемента. Таким образом, взвешенный размер останется неизменным. – CBass

+0

Точно так я предполагаю, что, поскольку 'weightedSize()' как и ожидалось, предыдущие элементы выселяются, как ожидалось. – Jin

Смежные вопросы