2012-06-19 13 views
10

¿Alguien sabe cuál es la sobrecarga de memoria de un ConcurrentHashMap (en comparación con un HashMap "clásico")?Sobrecarga de memoria ConcurrentHashMap

  • En construcción?
  • ¿En la inserción de un elemento?
+0

No tiene sentido crear una gran cantidad de ConcurrentHashMap dado que solo tiene un número limitado de núcleos. La sobrecarga de un pequeño número de CHM es probable que tenga menos de 1 centavo de memoria. –

+0

@PeterLawrey Realmente no entiendo tu punto. "Es inútil crear una gran cantidad de ConcurrentHashMap", ¿y qué? Aún tienen una sobrecarga. Además, incluso si es obviamente extraño tener muchos CHM al mismo tiempo, uno puede imaginar fácilmente que los objetos de vida corta crean un mapa hash simultáneo en su construcción (digamos un operador de unión en un software orientado a DB?). – Maxime

+0

Una razón por la que podría usar colecciones concurrentes es porque tiene más núcleos que colecciones. Si tiene muchas más colecciones que núcleos, es muy poco probable que tenga acceso concurrente. –

Respuesta

6

Si ejecuta lo siguiente con -XX:-UseTLAB -XX:NewSize=900m -mx1g en una JVM de 64 bits.

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(); 
} 

que obtiene con Java 6 y 7 para un millón de entradas.

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. 

Ocho MB de memoria cuesta alrededor de 5 centavos.

+0

¿Qué tan confiable es esa medición del uso de la memoria? – assylias

+0

¿Puede explicarnos el punto de utilizar asignaciones locales de subprocesos? ¡Gracias! – assylias

+0

Puede ser diferente en Java 5 u otras JVM que HotSpot o OpenJDK, pero me sorprendería si es significativamente diferente. La diferencia podría ser menor en las JVM de 32 bits. –

2

Realmente no entiendo la premisa de la pregunta: o necesita la simultaneidad o no.

Sin embargo, de acuerdo con this link, la huella de memoria de un ConcurrentHashMap vacío es de 1700 bytes. Le recomendamos que utilice el ConcurrentHashMap si tiene varios hilos que necesitan acceso de lectura/escritura, pero un Hashtable si tiene muchos hilos que necesitan acceso de lectura, pero uno con escritura.

+0

El enlace es demasiado viejo para ser relevante. De hecho, este artículo fue publicado (28/04/2012) antes de Java 7 y la implementación probablemente haya cambiado. Además, su respuesta es incompleta ya que solicito la inserción también (¿hay alguna?). – Maxime

+2

@Maxime La implementación probablemente no ha cambiado tanto, pero en cualquier caso, describe el método que utilizaron para encontrar los datos. Un poco de investigación muestra que nadie más lo ha hecho aún. – purtip31

4

ConcurrentHashMap no utiliza mucha más memoria que HashMap, tanto en la construcción como en la inserción.

En intialization

ConcurrentHashMap utiliza casi la misma cantidad de memoria como un HashMap, puede ser un poco más por un par de variables y cerraduras adicionales de teneduría de libros.

Durante la inicialización, ConcurrentHashMap crea 16 segmentos para almacenar valores-clave, cada segmento es equivalente a un HashMap.

La capacidad/tamaño inicial de cada segmento es 1/16 de la capacidad inicial total. Así que, en esencia, ConcurrentHashMap crea 16 pequeños HashMaps equivalentes a un HashMap. Cada segmento tiene su propio candado y un par de variables de contabilidad (conteo, umbral, etc.), esto es una sobrecarga de memoria adicional.

Se puede controlar el número de segmentos creados por ConcurrentHashMap pasando valor apropiado a parámetro concurrencyLevel a la ConcurrentHashMap. Cuanto menor sea este valor, menos espacio se utilizará, pero más contención cuando un alto número de hilos actualice el mapa. Cuanto más alto sea este valor, más segmentos se crearán, pero el rendimiento de las actualizaciones paralelas será más rápido. Nota: El valor significativamente mayor para concurrencyLevel parámetro, afecta el espacio y el tiempo.

Esta pequeña sobrecarga en la memoria es lo que un desarrollador está dispuesto a aceptar a cambio de concurrencia.

En Inserción

cuando los segmentos se llenan, se incrementará el tamaño de ese segmento. La política para aumentar el tamaño es la misma que HashMap. loadfactor parámetro decide cuándo aumentar el tamaño del segmento. Tenga en cuenta solo que el segmento que se llena se incrementará.Una vez más, la sobrecarga de memoria es casi igual a HashMap.

En general, ConcurrentHashMap no usa mucha más memoria que HashMap, pero es realmente difícil medir cada byte adicional utilizado por ConcurrentHashMap.

Cuestiones relacionadas