java - Sobrecarga de memoria de ConcurrentHashMap
memory-profiling (3)
Realmente no entiendo la premisa de la pregunta: o necesitas la concurrencia o no.
Sin embargo, según este enlace , 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.
¿Alguien sabe cuál es la sobrecarga de memoria de un ConcurrentHashMap (en comparación con un HashMap "clásico")?
- En la construcción?
- En la inserción de un elemento?
ConcurrentHashMap
no usa mucha más memoria que HashMap
, tanto en la construcción como en la inserción.
En la Intialización
ConcurrentHashMap
utiliza casi la misma cantidad de memoria que un HashMap, puede ser un poco más para un par de variables y bloqueos adicionales.
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. 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.
Puede controlar la cantidad de Segmentos creados por ConcurrentHashMap
pasando el valor apropiado al parámetro concurrencyLevel a 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 el parámetro concurrencyLevel 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 la inserción
Cuando los segmentos se llenen, se aumentará el tamaño de ese segmento. La política para aumentar el tamaño es la misma que HashMap. El parámetro loadfactor 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
.
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();
}
obtienes Java 6 y 7 por 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.