Buscar
Social
Ofertas laborales ES
« Nuevo tutorial: Google Cloud EndPoints Parte II | Main | APIdays Mediterranea en Barcelona el 29 y 30 mayo »
lunes
abr282014

Implementación de un HashMap que almacena los datos fuera del heap para Java 8

Desde Java 6 existen formas de almacenar datos en memoria desde un programa Java que están fuera del heap, y que por lo tanto no son analizados por el recogedor de basura cada vez que tiene que liberar memoria RAM. 

Almacenar datos fuera del heap es algo que puede incrementar considerablemente el rendimiento de una aplicación si estos datos tienen un gran tamaño y son datos que vamos a usar durante mucho tiempo, por lo que van a sobrevivir un montón de pasadas del recogedor de basura. Estos datos pueden incrementar considerablemente el tamaño del heap, y por tanto el trabajo que tiene que realizar el recogedor de basura, para no terminar liberando nada de su memoria ya que son datos que van a tener una vida muy larga. De ahí el interés de contar con una región de memoria que no va a ser examinada por el recogedor de basuras.

Me he encontrado en GitHub una implementación de un HashMap que almacena los datos fuera del  heap para Java 8. Sólo almacena datos de tipo binario (array de bytes). Pero puede ser una forma muy sencilla y rápida de almacenar datos fuera del heap en nuestra aplicación sin tener que usar directamente este API.

¿Alguna vez habéis tenido problemas de rendimiento en una aplicación vuestra precisamente por tener una gran cantidad de datos en memoria que causaba pausas por culpa del recogedor de basuras?

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (7)

Viendo la implementación, parece que el autor usa misc.unsafe para escribir off-heap.
Unsafe no es parte de la API pública de Java y hay que acceder a ella a través de reflexión. Tampoco veo que haya nada nuevo en Java8 respecto a este tema.

abril 28, 2014 | Unregistered Commenterj

Interesante, muy interesate... pero IMHO para usar con precaución (o mejor, no usarlo y saber que está ahí por si acaso).

Que por cierto, estoy muy torpe, por que no veo que relacción tiene con Java 8, ¿Hay alguna referencia de cómo se han oficializado estas APIS, o dónde están documentadas? ¿alguien nos puede ilustrar?

Del proyecto BinaryOffheapHashMap inspeccionando el código está usando las clases sun.misc.Unsafe, concretamente accediendo a un miembro privado por reflexion...


private Unsafe getUnsafe() {
try {
Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
singleoneInstanceField.setAccessible(true);
return (Unsafe) singleoneInstanceField.get(null);
} catch (IllegalArgumentException | SecurityException | NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e.getMessage(), e);
}
}


...
// This is the location of the partition on which the entry key belongs
long locationAddress = unsafe.getAddress(partitionAddress + (offset * addressSize));

// Skip if unallocated
if (locationAddress == 0)
return null;

// Read how many entries we expect in this partition
int entryCount = unsafe.getInt(locationAddress);
...

La "trampa sucia" que hace para escapar del heap es usar la clase Unsafe, que no está documentada, ¿ni en Java 8?

Dejo aquí un , un artículo sobre el uso de "unsafe" en java (Java7).

Salu2

abril 28, 2014 | Registered Commenterandrese

si me lo he encotnrado, precisamente con un HashMap, y lo solucione creandome un interface parecido al de HashTable (put, get, contains...) y varias clases que lo implmentaban guardando los datos en una combinacion de memoria y ficheros, nosql...

Mi problema principalmente era el tamaño de lo que se guardaba mas que la velocidad, pero se notaba la mejora en el GC.

abril 28, 2014 | Registered Commenternilojg

Buenas,

A mi lo que he leido me plantea varias cuestiones:

almacena los datos fuera del heap

Entiendo que sera fuera del heap gestionado por la JVM no? La memoria se movera al heap no gestionado del proceso .

...para Java 8

????? Porque para Java 8 si ya se podia hacer perfectamente antes.

estas API internas no documentadas se han convertido en API oficiales.

Como dice@andrese: donde podemos ver una referencia a esa documentacion oficial de las API

Estos datos pueden incrementar considerablemente el tamaño del heap, y por tanto el trabajo que tiene que realizar el recogedor de basura

Que yo sepa lo que recorre el recolector de basura es el arbol de referencias partiendo del root. No recorre todo el heap gestionado examinando los objetos. Si encuentra una referencia no utilizada simplemente marca la direccion referenciada como libre.
Como mucho, puede tener consecuencias de compactar el espacio de vida larga (ternured) cuando esta fragmentado, operacion que no se realiza normalmente en cada GC, que solo se realiza en las zonas del heap necesarias y que por otro lado puede ser configurada al lanzar la JVM.
http://apmblog.compuware.com/2011/05/11/how-garbage-collection-differs-in-the-three-big-jvms/


Un saludo

abril 29, 2014 | Unregistered CommenterUnoPorAhi

Mea culpa respecto a lo del API no es oficial en Java 8 tampoco, aunque hay gente que está tratando de hacer una propuesta Para hacer oficial el API; más información aquí:

https://groups.google.com/forum/#!forum/jep-off-heap

Respecto al tema de que tener un heap de gran tamaño es un problema, si el heap tiene un tamaño grande por lo tanto habrá muchas referencias (a no ser que tengas muy pocos objetos enormes, cosa rara) y por lo tanto va a tener que usar mucho tiempo para recorrer todo el árbol de referencias. Es interesante la lectura de esto al respecto:

http://www.javahispano.org/antiguo_javahispano_org/2008/6/6/escalando-aplicaciones-jee-el-caso-de-linkedin.html

No sé si es la arquitectura actual de Linkedin (probablemente haya cambios) pero es interesante lo que dicen sobre su cache de 12 GB:

"El cache está implementado en C++ y se usa JNI para accederlo desde Java. Han elegido C++ para usar tan poca RAM como sea posible y porque las pausas del Garbage Collector si usaban Java eran mortales."

abril 29, 2014 | Registered CommenterAbraham

Buenas,

Pues tienes razon. Sorry. Por leer y pensar en diagonal estaba pensando en un objeto enorme y no en una estructura HashMap.

Respecto al caso LinkedIN, resulta muy superinteresante el tratamiento de la cache que comentas. Las pausas tienen que ser enormes para que sea mas rentable acceder por interfaces JNI! En dicho claso esta claro que unsafe seria una mejor opcion.

Sin embargo, yo creo que tiene que haber otros workarounds para solucionar estos problemas y que salir del ambiente gestionado deberia ser la ultima opcion. En el mismo LinkedIn ha llovido mucho desde 2008 y esta claro que se han hecho muy expertos en el arte de tunear el GC:
http://engineering.linkedin.com/garbage-collection/garbage-collection-optimization-high-throughput-and-low-latency-java-applications

Estaria bien saber que tipo de solucion utilizan ahora.

Un saludo

abril 29, 2014 | Unregistered CommenterUnoPorAhi

Abraham, tienes el link a esa cita que comentas de Linkedin sobre la caches de 12Gb?

En mi proyecto las caches de algunas máquinas son de +60Gb. La mayoría de las garbage collections son concurrentes sin impacto alguno, pero si cae alguna major collection (igual 1 al día)... el mundo se para por un buen rato, sí ;)

abril 30, 2014 | Unregistered Commenterj

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>