2009-10-29 12 views
5

Quiero crear un LinkedHashMap que limitará su tamaño en función de la memoria disponible (es decir, cuando freeMemory + (maxMemory - allocatedMemory) se encuentre por debajo de un determinado umbral). Esto se usará como una forma de caché, probablemente utilizando el "uso menos reciente" como estrategia de almacenamiento en caché.LRU LinkedHashMap que limita el tamaño según la memoria disponible

Mi preocupación es que la memoria asignada también incluye (supongo) los datos recolectados sin basura, y así sobreestimar la cantidad de memoria utilizada. Me preocupan las consecuencias involuntarias que esto podría tener.

Por ejemplo, LinkedHashMap puede seguir eliminando elementos porque cree que no hay suficiente memoria libre, pero la memoria libre no aumenta porque estos elementos eliminados no se recogen de forma inmediata.

¿Alguien tiene alguna experiencia con este tipo de cosas? ¿Está justificada mi preocupación? Si es así, ¿alguien puede sugerir un buen enfoque?

Debo agregar que también quiero ser capaz de "bloquear" la memoria caché, básicamente diciendo "ok, a partir de ahora no elimine nada debido a problemas de uso de memoria".

+0

¿Cuál es su aplicación aquí? Es difícil encontrar una buena respuesta sin una idea de cuál es la intención de fondo. ¿Es su HashMap un caché o qué? – jprete

+0

jprete, traté de aclarar esto, tiene razón, es un caché – sanity

+0

Este es un ejemplo típico de cómo GC y la administración de la memoria Java muestran su cara realmente desordenada. Sería * tan simple * hacer tal cosa en C++. Usando GC, no puedes ejecutar comandos como eliminar o liberar. –

Respuesta

1

Sé que soy parcial, pero realmente tengo que recomendar encarecidamente nuestro MapMaker para esto. Use la función softKeys() o softValues ​​(), dependiendo de si es la recopilación de GC de la clave o del valor que describe más acertadamente cuando se puede limpiar una entrada.

+1

Me gustaría usar MapMaker (hago un uso extensivo de Google Collections en mi código), pero ¿hay alguna manera de hacer que se comporte como un caché LRU que escala según la memoria disponible? Además, ¿hay alguna manera de "bloquearlo" para que ya no elimine las entradas en respuesta a la recolección de basura? – sanity

+1

"comportarse como un caché LRU ..." - eso describe bastante bien exactamente lo que las referencias suaves le darán, sí. "bloquearlo" - la única respuesta sensata a esto implica copiar el mapa: Map < Key, Val > strongCache = Maps.newHashMap (cache); –

+0

disculpa por la basura <; no hay vista previa, así que tuve que adivinar si tendría que escapar o no. :( –

0

Los cachés tienden a ser problemáticos. IIRC, hay un SoftCache en Sun's JRE que ha tenido muchos problemas.

De todos modos, lo más simple es usar SoftReference s en el mapa. Esto debería funcionar bien siempre que la sobrecarga de SoftReference más Map.Entry sea significativamente menor que los datos en caché.

También puede, como WeakHashMap, usar un ReferenceQueue y sondearlo o tener un bloqueo de hilo en él (un hilo por instancia, desafortunadamente). Tenga cuidado con los problemas de sincronización.

"Bloqueando" el mapa, es probable que desee evitarlo si es necesario. Debería mantener fuertes referencias a todos los datos (y desalojar si no es nulo). Eso va a ser feo

+0

Para el bloqueo, estaba pensando que podía simplemente copiar todo en un HashMap normal – sanity

+0

Bueno, puede copiar el contenido del mapa, pero también debe eliminar las referencias suaves. Aunque copiar en lugar de bloquear es una mejor forma de hacerlo. –

0

Sugeriría usar algo como Ehcache en lugar de reinventar un sistema de almacenamiento en caché. Es súper simple de usar, muy configurable y funciona muy bien.

0

Como dijo matt b, algo como Ehcache o JbossCache es un buen primer paso.

Si desea algo ligero y en proceso, consulte las colecciones de google. Por ejemplo, puede usar MapMaker (http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/BiMap.html) para hacer un mapa con claves y valores Suaves/Débiles, por lo que solo almacenaría en caché los elementos para los que tiene espacio (aunque no obtendría LRU).

+0

Oops - mejor enlace: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/MapMaker.html – nojo

0

que tenía la misma necesidad en el pasado y así es como he implementado mi caché:

  • hay un gestor de memoria caché, que tiene un mínimo y un límite máximo de memoria (máx limitarlo importa de todos modos)
  • cada caché registrado tiene los siguientes parámetros (importantes): capacidad máxima (la mayor parte del tiempo que tiene un límite más alto, usted no quiere ir contener más de X material) el uso de memoria & ciento
  • que utilizo un LinkedHashMap y un ReentrantReadWriteLock para proteger el caché.
  • cada X pone Calculo el consumo medio de memoria por entrada y activa el desalojo (asincrónico) si el límite de memoria calculado> permite el límite de memoria.
  • Por supuesto, el cálculo de la memoria no muestra realmente el consumo de memoria real, pero al comparar la memoria calculada con el valor real (usando un generador de perfiles) me parece que está lo suficientemente cerca.

Estaba planeando poner también un protector adicional en el caché, para desalojar en caso de que las puts sean más rápidas que los desalojos basados ​​en memoria, pero hasta ahora no he encontrado la necesidad de hacerlo.

Cuestiones relacionadas