2010-05-11 26 views
36

Considere el código HashMap.clear() siguientes aparatos:¿Está vigente la memoria Java HashMap.clear() y remove()?

/** 
* Removes all of the mappings from this map. 
* The map will be empty after this call returns. 
*/ 
public void clear() { 
    modCount++; 
    Entry[] tab = table; 
    for (int i = 0; i < tab.length; i++) 
     tab[i] = null; 
    size = 0; 
} 

Parece, que la matriz interna (table) de Entry objetos no se achica. Entonces, cuando agregue 10000 elementos a un mapa, y luego de eso llame al map.clear(), mantendrá 10000 nulos en su matriz interna. Entonces, mi pregunta es, ¿cómo maneja JVM esta matriz de nada, y por lo tanto, es efectiva la memoria HashMap?

+5

10.000 nulos ocupan todos los 40 KB (posiblemente 80 en una JVM de 64 bits). –

+8

@Michael, tal vez, pero eso es irrelevante: el número se puede ampliar a cualquier escala. OP está preguntando por una cuestión de principios. Tal vez el mapa es enorme, tal vez la memoria disponible es pequeña. No lo sabemos – corsiKa

+2

10000 elementos en el mapa! = 10000 entradas en la tabla interna. aprenda cómo funciona la herramienta HashMap primero ... – james

Respuesta

57

La idea es que clear() solo se invoca cuando desea volver a utilizar HashMap. La reutilización de un objeto solo debe hacerse por la misma razón que antes, por lo que es probable que tenga aproximadamente el mismo número de entradas. Para evitar el encogimiento y cambio de tamaño inútiles del Map, la capacidad se mantiene igual cuando se llama al clear().

Si todo lo que quiere hacer es descartar los datos en el Map, entonces no se necesita (y de hecho no debe) llamar clear() en él, sino simplemente en claro todas las referencias al Map sí, en cuyo caso serán basura recolectada eventualmente

+0

También me gustaría añadir que este comportamiento no forma parte del contrato documentado, por lo que incluso si se tropezó con la implementación que * sí * redimensionó la matriz interna, lo que parece poco probable, entonces usted probablemente no debería confiar en eso a menos que explícitamente lo haga parte del contrato. –

+1

Eso está bien, pero ¿qué pasa si el HashMap se usa en algún tipo de singletone, y siempre contiene algunos datos, por lo que no puede ser simplemente reemplazado por una nueva instancia? En algunos casos, puede obtener una gran porción de datos, que vivirán allí por un tiempo, y luego se eliminarán. Pero los nulos en la matriz se mantendrán. Eso no se ve bien –

+5

@Shaman: todo lo que acaba de dar es otra razón para no utilizar el patrón singelton ;-) –

4

Tiene razón, pero teniendo en cuenta que aumentar la matriz es una operación mucho más costosa, no es irracional que HashMap piense que "una vez que el usuario incrementó la matriz, es probable que necesite la matriz de este tamaño otra vez más tarde". "y simplemente deje la matriz en lugar de disminuirla y arriesgándose a tener que expandirla costosamente más tarde otra vez". Supongo que es una heurística. También puedes abogar por el otro camino.

4

Otra cosa a considerar es que cada elemento en table es simplemente una referencia. Establecer estas entradas en nulo eliminará las referencias de los elementos en su Map, que luego serán libres para la recolección de basura. Entonces no es como si no estuvieras liberando ningún tipo de memoria.

Sin embargo, si necesita liberar incluso la memoria utilizada por el Map en sí, entonces debe liberarla según la sugerencia de Joachim Sauer.

9

Looking at the source code, parece que HashMap nunca encoge. Se llama al método resize para duplicar el tamaño siempre que sea necesario, pero no tiene nada ala ArrayList.trimToSize().

Si estás utilizando un HashMap de tal manera que crece y se reduce drásticamente a menudo, es posible que desee simplemente crear una nueva HashMap en lugar de llamar clear().