Quando nel cestino contenuti HashMap per evitare il degrado delle prestazioni?
-
19-09-2019 - |
Domanda
Sono woking su Java con una grande HashMap (milioni) che è in realtà costruito con una capacità di 10.000.000 e un fattore di carico di 0,75 ed è utilizzato per memorizzare nella cache alcuni valori
poiché i valori memorizzati nella cache diventano inutili col tempo (non acceduto più), ma non riesco a rimuovere quelle inutili, mentre sulla strada mi piacerebbe completamente vuota la cache quando le sue prestazioni comincia a degradare. Come posso decidere quando è buono per farlo?
Ad esempio, con una capacità di 10 milioni di persone e .75 devo svuotarlo quando raggiunge 7,5 milioni di elementi? Perché ho provato diversi valori soglia ma desidero avere uno analitico.
Ho già provato il fatto che emping quando è abbastanza completo è una spinta per perfomance (primi 2-3 iterazioni algoritmo dopo la salvietta appena riempirlo di nuovo, allora comincia a correre più velocemente rispetto a prima della wipe)
EDIT: Ulteriori informazioni
Il hashmap trovi lungo come chiavi e galleggiante come valori. Esso contiene la correlazione cache di contenuti, dal momento che si tratta di un prodotto scalare di vettori tag ho voluto mettere in cache loro (per aumentare le prestazioni).
Quindi, in pratica quello che faccio è quello di calcolare una chiave long
utilizzando i codici hash dei contenuti 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;
}
e utilizzarlo per recuperare i valori memorizzati. Quello che succede è che, poiché si tratta di un clustering gerarchico contenuti vengono uniti ei loro valori di correlazione con altri contenuti non sono necessari più .. è per questo che voglio pulire il HashMap di tanto in tanto, per evitare il degrado a causa di valori inutili al suo interno.
Utilizzando un WeakHashMap
sarà imprevedibilmente cancellare i dati anche quando sono ancora necessari .. non ho controllo su di esso.
Grazie
Soluzione
Perché non usare un LRU cache? Dalla documentazione LinkedHashMap di Java:
Un costruttore speciale è previsto per creare una mappa di hash legato il cui ordine di iterazione è l'ordine in cui il suo voci stati aperti, da meno di recente accesso a più di recente (accesso-ordine). Questo tipo di carta è particolarmente adatto alla costruzione cache LRU. Invocare put o ottenere metodo comporta un accesso alla corrispondente voce (supponendo che esiste dopo l'invocazione completa). Il metodo putAll genera una voce per ogni accesso mappatura nella mappa specificato, nel ordinare che mappature chiave-valore sono fornito dalla ingresso della mappa specificata iteratore set. Non ci sono altri metodi generare ingresso accessi. Nel particolare, le operazioni di raccolta-vista non influiscono sulla ordine di iterazione della mappa di backup.
Quindi, fondamentalmente, ogni tanto un po 'come il vostro mappa diventa troppo grande, basta eliminare i primi valori di x che l'iteratore ti dà.
Si veda la documentazione per removeEldestEntry
di avere questo fatto per voi automaticamente.
Ecco il codice che dimostra:
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}
}
Altri suggerimenti
Avete indagato WeakHashMaps ? Il garbage collector può determinare quando per rimuovere cose e può dare un sostituto accettabile piuttosto che codifica qualcosa di te stesso.
Questo articolo ha informazioni più utili.
Si consiglia di utilizzare Google Collezioni MapMaker per fare una mappa con riferimenti morbide e un timeout specifica.
I riferimenti soft "vengono cancellati a discrezione del garbage collector in risposta alla domanda di memoria".
Esempio:
ConcurrentMap<Long, ValueTypeHere> cacheMap = new MapMaker()
.concurrencyLevel(32)
.softValues()
.expiration(30, TimeUnit.MINUTES)
.makeMap();
È inoltre possibile specificare weakKeys se si vuole fare i suoi tasti si comportano come quelle di un WeakHashMap.