2012-06-19 19 views
10

Qualcuno sa qual è il sovraccarico di memoria di una ConcurrentHashMap (rispetto a una "classica" HashMap)?Overhead memoria concurrentHashMap

  • In costruzione?
  • All'inserimento di un elemento?
+0

Non ha senso creare un numero elevato di ConcurrentHashMap e avere solo un numero limitato di core. Il sovraccarico di un piccolo numero di CHM è probabilmente inferiore a 1 centesimo di memoria. –

+0

@PeterLawrey Non capisco davvero il tuo punto. "È inutile creare una grande quantità di ConcurrentHashMap", e allora? Hanno ancora un sovraccarico. Inoltre, anche se è ovviamente strano avere molti CHM allo stesso tempo, si può facilmente immaginare che gli oggetti a vita breve creino una mappa di hash simultanea alla loro costruzione (diciamo un operatore di join in un software orientato al DB?). – Maxime

+0

Un motivo per cui è possibile utilizzare le raccolte concorrenti è perché si hanno più core delle raccolte. Se disponi di molte più raccolte rispetto ai core, è altamente improbabile che tu abbia accesso concorrente. –

risposta

6

Se si esegue quanto segue con -XX:-UseTLAB -XX:NewSize=900m -mx1g su una JVM a 64 bit.

public static void main(String... args) throws NoSuchMethodException, IllegalAccessException { 
    for (int i = 0; i < 4; i++) { 
     long used1 = usedMemory(); 
     populate(new HashMap()); 
     long used2 = usedMemory(); 
     populate(new ConcurrentHashMap()); 
     long used3 = usedMemory(); 
     System.out.println("The ratio of used memory is " + (double) (used3 - used2)/(used2 - used1)); 
     System.out.println("For an extra " + ((used3 - used2) - (used2 - used1))/1000000 + " bytes per entry was used."); 
    } 
} 

private static void populate(Map map) { 
    for (Integer i = 0; i < 1000000; i++) 
     map.put(i, i); 
} 

private static long usedMemory() { 
    return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 
} 

si ottiene con Java 6 e 7 per un milione di voci.

The ratio of used memory is 1.1291128466982379 
For an extra 8 bytes per entry was used. 
The ratio of used memory is 1.1292086928728067 
For an extra 8 bytes per entry was used. 
The ratio of used memory is 1.1292086928728067 
For an extra 8 bytes per entry was used. 
The ratio of used memory is 1.1292086928728067 
For an extra 8 bytes per entry was used. 

Otto MB di memoria costa circa 5 centesimi.

+0

Quanto è affidabile la misurazione dell'uso della memoria? – assylias

+0

Puoi spiegare il punto di utilizzo delle allocazioni locali dei thread? Grazie! – assylias

+0

Potrebbe essere diverso su Java 5 o altre JVM rispetto a HotSpot o OpenJDK ma mi sorprenderebbe se fosse significativamente diverso. La differenza potrebbe essere inferiore su JVM a 32 bit. –

2

Non capisco davvero la premessa della domanda - o hai bisogno della concorrenza o non lo fai.

Tuttavia, in base allo this link, il footprint di memoria di uno ConcurrentHashMap vuoto è 1700 byte. Ti consigliamo di utilizzare ConcurrentHashMap se hai più thread che richiedono l'accesso in lettura/scrittura, ma uno Hashtable se hai molti thread che necessitano di accesso in lettura ma uno con scrittura.

+0

Il collegamento è troppo vecchio per essere rilevante. Infatti, questo articolo è stato pubblicato (28/04/2012) prima di Java 7 e l'implementazione è probabilmente cambiata. Inoltre, la tua risposta è incompleta poiché chiedo anche l'inserimento (ce n'è uno). – Maxime

+2

L'implementazione @Maxime probabilmente non è cambiata molto, ma in ogni caso descrive il metodo utilizzato per trovare i dati. Un po 'di ricerche dimostrano che nessun altro l'ha ancora fatto. – purtip31

4

ConcurrentHashMap non utilizza molto più memoria di HashMap, sia in fase di costruzione che di inserimento.

A Intialization

ConcurrentHashMap utilizza quasi la stessa quantità di memoria come HashMap, può essere un po 'più per un paio di variabili e serrature di contabilità in più.

Durante l'inizializzazione, ConcurrentHashMap crea 16 segmenti per memorizzare valori-chiave, ciascun segmento è equivalente a una HashMap.

La capacità/dimensione iniziale di ciascun segmento è pari a 1/16 della capacità iniziale complessiva. Quindi, in sostanza, ConcurrentHashMap crea 16 piccoli HashMaps equivalenti a una HashMap. Ogni segmento ha il proprio blocco e un paio di variabili di contabilità (conteggio, soglia ecc.), Questo è un sovraccarico di memoria extra.

È possibile controllare il numero di segmenti creati da ConcurrentHashMap passando valore appropriato per concurrencyLevel parametro al ConcurrentHashMap. Più piccolo è questo valore, quindi verrà utilizzato meno spazio ma più contesa quando un numero elevato di thread aggiorna la mappa. Aumentando questo valore, verranno creati più segmenti, ma le prestazioni degli aggiornamenti paralleli saranno più veloci. Nota: un valore significativamente più elevato per il parametro concurrencyLevel interessa sia lo spazio che il tempo.

Questo piccolo sovraccarico in memoria è ciò che uno sviluppatore è disposto ad accettare in cambio di concorrenza.

all'inserimento

quando i segmenti si riempiono, sarà aumentata la dimensione di quel segmento. La politica per aumentare le dimensioni è la stessa di HashMap. loadfactor parametro decide quando aumentare la dimensione del segmento. Nota solo che il segmento che è stato riempito sarà aumentato.Ancora una volta, l'overhead della memoria è quasi lo stesso di HashMap.

Complessivamente, ConcurrentHashMap non utilizza molto più memoria di HashMap, ma è davvero difficile misurare ogni byte in più utilizzato da ConcurrentHashMap.