2014-10-29 3 views
1

Я вижу ниже реализацию кэша LRU в устаревшем проекте, где у меня есть вопрос об использовании SoftReference для объекта value, но не для ключевого объекта.Использование SoftReference в Map?

Вот реализация

public class LRUCacheImpl<K, V> implements LRUCache<K, V> { 

// SoftReference is used for a memory friendly cache. 
// The value will be removed under memory shortage situations and 
// the keys of the values will be removed from the cache map. 
private final Map<K, SoftReference<V>> cache; 


public LRUCacheImpl(final int cacheSize) { 

    // 'true' uses the access order instead of the insertion order. 
    this.cache = new LinkedHashMap<K, SoftReference<V>> (cacheSize, 0.75f, true) { 

    private static final long serialVersionUID = 1L; 

    @Override 
    protected boolean removeEldestEntry(Map.Entry<K, SoftReference<V>> eldest) { 
    // When to remove the eldest entry i.e. Least Recently Used (i.e. LRU) entry 
    return size() > cacheSize; // Size exceeded the max allowed. 
    } 
    }; 
} 

@Override 
public V put(K key, V value) { 
    SoftReference<V> previousValueReference = cache.put(key, new SoftReference<V>(value)); 
    return previousValueReference != null ? previousValueReference.get() : null; 
} 

@Override 
public V get(K key) { 
    SoftReference<V> valueReference = cache.get(key); 
    return valueReference != null ? valueReference.get() : null; 
} 
} 

ГХ высвобождает память для мягко достижимых объектов, если приложение о том, чтобы достичь OutOfMemory (OOM). Если я применяю ту же логику, только память для значения должна быть восстановлена ​​(поскольку мягкая ссылка создается только для объекта значения).
Но вот комментарий в начале файла

// SoftReference is used for a memory friendly cache. 
// The value will be removed under memory shortage situations and 
// the keys of the values will be removed from the cache map. 

Мой вопрос, как соответствующий ключевой объект будет удален с карты один раз приложение рич ООМ. Не следует ли обертывать ключ с мягкой ссылкой?

cache.put(new SoftReference<K>(key), new SoftReference<V>(value)); 
+0

'Key' ожидает быть меньше по размеру по сравнению с величиной, поэтому делает ключ, как мягкий исх не помогает много –

+0

ли коду, который вы разместили полный класс? Метод 'removeEldestEntry' подразумевает, что количество ключей на этой карте должно быть ограничено' cacheSize', но я не вижу, чтобы это принудительно выполнялось где угодно. – Eran

+0

@Eran Это полный код. removeEldestEntry вызывается внутренне, а операция put – user3198603

ответ

2

Я не знал о том, что LinkedHashMap поддерживает ограничение размера карты. Внедряя removeEldestEntry, вы не позволяете карте удерживать более cacheSize ключей.

Как вы можете видеть в реализации LinkedHashMap, добавление новой записи приводит к удалению старшей записи, если removeEldestEntry возвращает true.

void addEntry(int hash, K key, V value, int bucketIndex) { 
    createEntry(hash, key, value, bucketIndex); 

    // Remove eldest entry if instructed, else grow capacity if appropriate 
    Entry<K,V> eldest = header.after; 
    if (removeEldestEntry(eldest)) { 
     removeEntryForKey(eldest.key); 
    } else { 
     if (size >= threshold) 
      resize(2 * table.length); 
    } 
} 

Следовательно, наименее используемые ключи будут удалены с карты.

С помощью этого конструктора:

this.cache = new LinkedHashMap<K, SoftReference<V>> (cacheSize, 0.75f, true) 

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

Таким образом, //the keys of the values will be removed from the cache map, вероятно, ссылается на то, что наименее используемые ключи в конечном итоге будут удалены с карты, независимо от удаления значений под нехваткой памяти.

+0

извините за поздний комментарий. Но мой вопрос здесь: «Не должен ли ключ быть обернут с помощью мягкой ссылки?», А не просто значения в случае отсутствия памяти, так что ключ и значения удаляются? – user3198603

0

Упаковочные ключи в Reference s является опцией, если она запутана.
Цель состоит в том, чтобы избежать OOM, в то же время не прибегая к какому-либо недостатку, заключающемуся в том, чтобы не получать значения из кеша, чтобы отпустить их ненужно.
Просто оберточной ключи в Reference с недостаточно стандартных реализаций карты -
без перекрывая equals() & hashCode(), ни одна клавиша не будет отображаться равно: ничто не обнаружено, заменить, удалить, ...
Другой подход заключается в использовании Soft/WeakReference с с Map.Entry s: см. java.util.WeakHashMap<K, V> для примера того, как это сделать (со ссылкой на ключ, кстати). Преимущество состоит в том, что вы можете избавиться от любых оставшихся сильных ссылок, как только заметите, что мягкий/слабый ушел.
Тогда есть trove4j, Apache Commons Collections, Goldman Sachs ...

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