borrar - java cache library
¿Cómo puedo almacenar en caché eficientemente objetos en Java utilizando la memoria RAM disponible? (12)
Necesito almacenar en caché los objetos en Java usando una proporción de cualquier RAM disponible. Soy consciente de que otros han hecho esta pregunta, pero ninguna de las respuestas cumple mis requisitos.
Mis requisitos son:
- Simple y ligero
- No mucho más lento que un HashMap simple
- Use LRU o alguna política de borrado que se aproxime a LRU
Probé LinkedHashMap, sin embargo, requiere que especifique una cantidad máxima de elementos, y no sé cuántos elementos se necesitarán para llenar la memoria RAM disponible (sus tamaños variarán significativamente).
Mi enfoque actual es usar el MapMaker de Google Collection de la siguiente manera:
Map<String, Object> cache = new MapMaker().softKeys().makeMap();
Esto parecía atractivo, ya que debería eliminar elementos automáticamente cuando necesita más memoria RAM, sin embargo, hay un problema grave: su comportamiento es llenar toda la memoria RAM disponible, momento en el que el GC comienza a agrietarse y el rendimiento de la aplicación se deteriora drásticamente.
He oído hablar de cosas como EHCache, pero parece bastante pesado para lo que necesito, y no estoy seguro de si es lo suficientemente rápido para mi aplicación (recordando que la solución no puede ser mucho más lenta que un HashMap) .
Esto parecía atractivo, ya que debería eliminar elementos automáticamente cuando necesita más RAM, sin embargo, hay un problema grave: su comportamiento es llenar toda la memoria RAM disponible.
El uso de teclas programables solo permite que el recolector de basura elimine objetos de la memoria caché cuando ningún otro objeto los referencia (es decir, cuando lo único que se refiere a la clave de la memoria caché es la memoria caché). No garantiza ningún otro tipo de expulsión.
La mayoría de las soluciones que encontrarás serán características agregadas sobre las clases de mapas de Java, incluido EhCache.
¿Has mirado los commons-collections LRUMap?
Tenga en cuenta que existe un problema abierto en contra de MapMaker para proporcionar funcionalidad LRU / MRU. Quizás también puedas expresar tu opinión allí
He oído hablar de cosas como EHCache, pero parece bastante pesado para lo que necesito, y no estoy seguro de si es lo suficientemente rápido para mi aplicación (recordando que la solución no puede ser mucho más lenta que un HashMap) .
Realmente no sé si se puede decir que EHCache es pesado. Al menos, no considero EHCache como tal, especialmente cuando uso un Almacén de Memoria (que está respaldado por un LinkedHashMap
extendido y es, por supuesto, la opción de almacenamiento en caché más rápida). Usted debe darle una oportunidad.
Creo que MapMaker
será la única forma razonable de obtener lo que está pidiendo. Si "el GC comienza a agitarse y el rendimiento de la aplicación se deteriora drásticamente", debe dedicar un tiempo a configurar correctamente los distintos parámetros de ajuste. Este documento puede parecer un poco intimidante al principio, pero en realidad está escrito muy claramente y es una mina de oro de información útil sobre GC:
http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf
En el pasado, he usado JCS . Puede configurar la configuration para tratar de satisfacer sus necesidades. No estoy seguro de si esto satisfará todos sus requisitos / necesidades, pero me pareció bastante poderoso cuando lo usé.
Implementé las memorias caché de serval y es probablemente tan difícil como implementar un nuevo origen de datos o subprocesos, mi recomendación es usar jboss-cache u otra conocida lib de caché. Así que dormirás bien sin problemas
No conozco una forma fácil de averiguar el tamaño de un objeto en Java. Por lo tanto, no creo que encuentre una forma de limitar una estructura de datos por la cantidad de RAM que está tomando.
En función de esta suposición, tiene que limitarse a la cantidad de objetos en caché. Sugeriría ejecutar simulaciones de algunos escenarios de uso de la vida real y recopilar estadísticas sobre los tipos de objetos que entran en el caché. Luego puede calcular el tamaño estadísticamente promedio y la cantidad de objetos que puede permitirse almacenar en caché. A pesar de que es solo una aproximación de la cantidad de RAM que desea dedicar a la memoria caché, podría ser suficiente.
En cuanto a la implementación de la memoria caché, en mi proyecto (una aplicación de rendimiento crítico) estamos usando EhCache, y personalmente no creo que sea pesado.
En cualquier caso, ejecute varias pruebas con varias configuraciones diferentes (con respecto al tamaño, política de desalojo, etc.) y descubra qué funciona mejor para usted.
No puede "eliminar elementos", solo puede detenerlos para hacer una referencia dura y esperar a que el GC los limpie, por lo tanto, continúe con Google Collections ...
No sé si esta sería una solución simple, especialmente si se compara con EHCache o similar, pero ¿has mirado la biblioteca de Javolution ? No está diseñado como tal, pero en el paquete javolution.context
tienen un patrón de Allocator que puede reutilizar objetos sin la necesidad de recolección de basura. De esta forma, mantienen la creación de objetos y la recolección de basura al mínimo, una característica importante para la programación en tiempo real. Tal vez deberías echarle un vistazo e intentar adaptarlo a tu problema.
Suponiendo que desea que el caché sea seguro para subprocesos, entonces debe examinar el ejemplo de caché en el libro de Brian Goetz "Concurrencia de Java en la práctica". No puedo recomendar esto lo suficiente.
Tengo requisitos similares para usted: concurrencia (en 2 CPU hexacore) y LRU o similar, y también probé Guava MapMaker. Encontré SoftValues () mucho más lento que weakValues (), pero ambos hicieron que mi aplicación fuera mucho más lenta cuando la memoria se llenó.
Intenté WeakHashMap y fue menos problemático, extrañamente incluso más rápido que usar LinkedHashMap como un caché LRU a través de su método removeEldestEntry ().
Pero el más rápido para mí es ConcurrentLinkedHashMap que ha hecho que mi aplicación sea 3-4 (!!) veces más rápida que cualquier otra memoria caché que probé. ¡Alegría, después de días de frustración! Aparentemente se ha incorporado al MapMaker de Guava, pero la función LRU no está en Guava r07 en cualquier caso. Espero que funcione para ti.
Usando su memoria caché existente, almacene WeakReference en lugar de refererencias de objetos normales.
Si el GC comienza a quedarse sin espacio libre, se liberarán los valores mantenidos por WeakReferences.
SoftReference
algo en caché, SoftReference
tal vez sea la mejor manera hasta ahora que puedo imaginar.
O puede reinventar un grupo de objetos. Que cada objeto que no usas, no necesitas destruirlo. Pero para ahorrar CPU en lugar de ahorrar memoria