Mostrando las entradas con la etiqueta jrockit. Mostrar todas las entradas
Mostrando las entradas con la etiqueta jrockit. Mostrar todas las entradas

martes, enero 18, 2011

La historia de jRockit, como ganar un concurso en la universidad te puede cambiar la vida

martes, enero 18, 2011 por Martín

Hace unos días recomendaba el libro Oracle JRockit: The Definitive Guide y comentaba que el prólogo contaba la historia de JRockit que publicaría en un nuevo post. Pues este es ese post :)

Para los no familiarizados con Java, jRockit es lo que se llama una máquina virtual. Es lo que ejecuta programas escritos en Java. Hoy en día muchísimos dispositivos vienen con una máquina virtual dentro, teléfonos móviles, coches, televisiones y por supuesto ordenadores. jRockit es una máquina virtual orientada a los ordenadores y principalmente a servidores.

El origen de jRockit es muy curioso a la vez que motivador para cualquier joven. En 1997, tres estudiantes universitarios llamados Joakim Dahlstedt, Mattias Joëlson y Fredrik Stridsman ganaron un concurso de programación para estudiantes organizado por Sun Microsystems y cuyo premio era un viaje a la JavaOne, la conferencia más importante de Java que se organiza en el mundo. Por diversión, volvieron a presentarse al año siguiente y volvieron a conseguir el premio.

jueves, enero 06, 2011

Oracle JRockit: The Definitive Guide

jueves, enero 06, 2011 por Martín

El último libro que he leido es este Oracle JRockit: The Definitive Guide y tengo que decir que ha sido una agradable sorpresa. Quienes conocéis este blog quizás recordéis algunos posts en el pasado sobre JRockit y Mission Control. Todos de la época en la que trabajaba con WebLogic (cuando todavía era de BEA) y JRockit era la máquina virtual recomendada.

El caso es que este libro cayó en mis manos. Además no de cualquier manera, sino que es un regalo de su autor Marcus Hirt. Además Marcus no es sólo el autor de este libro sino que además es que es uno de los creadores de JRockit, un proyecto que viene de su empresa Appeal Virtual Machines, más tarde comprada por BEA. La historia de este emprendimiento es muy interesante y me la guardo para otro post en breve. Mientras tanto os pongo la foto del libro que es que ¡además está firmado!

viernes, julio 13, 2007

BEA Mission Control un JConsole pero en mejor

viernes, julio 13, 2007 por Martín

Con la máquina virtual de BEA, JRockit, viene por defecto desde hace tiempo una aplicación llamada BEA Mission Control. Esta aplicación es como JConsole, es decir, que te permite monitorizar la máquina virtual y ver cosas como su consumo de memoria, CPU, información sobre los threads, o monitorizar los beans JMX entre otras cosas.

El caso es que Mission Control sorprende porque añade una serie de funcionalidades de lo más interesantes que lo convierten en una mejor alternativa a JConsole para sistemas que funcionan con la máquina virtual de BEA. Se trata de una aplicación desarrollada con Eclipse RCP y la verdad es que muestra la información de una manera más fácil de analizar y de digerir (por ejemplo la información sobre los threads se presenta de forma más útil).

Además, lo cierto es que te deja hacer cosas que no puedes hacer con JConsole como el hacer profile en tiempo real de tu aplicación viendo invocaciones a diferentes métodos y el tiempo que lleva realizarlas, o hacer profile para ver las excepciones que ocurren en el servidor, o por ejemplo detectar y que te muestre los diferentes deadlocks que se puedan estar produciendo entre threads.

En resumen, que vale la pena utilizarla si usáis JRockit. Tiene dos extensiones para grabar el "profiling" de la aplicación y analizarlo posteriormente y también un detector de memory leaks. Lo malo es que para esto ya entras en la versión de pago (y para usarlo en producción también).

Os dejo unas capturas de pantalla para los que nunca hayáis usado esta herramienta y queréis ver como es.




miércoles, julio 11, 2007

GC para tiempos bajos de respuesta (y II)

miércoles, julio 11, 2007 por Martín

Continuo y finalizo el post de ayer sobre recolección de basura en sistemas que necesitan tiempos rápidos de respuesta.

  1. Optimizar el tamaño de los TLABs : Esta es para nota. Un TLA (TLAB en Sun JDK, Jon Masamitsu escribió hace un año una excelente entrada sobre esto) es una zona de memoria en la que un thread tiene permiso exclusivo para acceder lo que significa que el thread puede reservar memoria sin ningún tipo de bloqueo por lo que el rendimiento es mayor.

    Configurar un tamaño adecuado de estos TLAs es algo complicado, de hecho se hace una tarea muy ardua sin una buena herramienta para controlar los cambios en el rendimiento, pero puede incrementar considerablemente el rendimiento.
  2. Ajustar el límite para la recolección de basura : Las recolecciones completas de basura no se realizan cuando el heap está lleno, ya que en ese momento se lanzaría una OutOfMemoryException, sino que se lanzan al llegar a un determinado límite. Las máquinas virtuales permiten cambiar ese límite.

    En ocasiones este límite puede ser demasiado bajo, y si realmente se conoce muy bien el funcionamiento de la aplicación se puede ajustar para que sea un poco mayor y de este modo quepan más objetos en memoria (con el consiguiente coste de recolección).
  3. Evitar la fragmentación y optimizar el ratio de compactación: Las máquinas virtuales sufren el mismo problema que la memoria física o los discos duros. El almacenamiento continuo de objetos crea fragmentación. Para solucionar esto, existe lo que se llama compactación. Periodicamente, con cada recolección de basura, la máquina virtual tratará de compactar algo del espacio del heap para que cojan más objetos.

    Las máquinas virtuales suelen ofrecer parámetros avanzados para configurar el modo en el que se compacta la memoria. Por ejemplo en JRockit es posible establecer el tanto por ciento de heap que se quiere compactar en cada recolección. Un porcentaje alto hará que se gaste mucho tiempo compactando, mientras que un porcentaje bajo puede incrementar demasiado la fragmentación, llegando incluso en el caso límite a provocar OutOfMemoryException cuando no hay más espacio para colocar objetos en memoria. Otra opción típica es en lugar de especificar el ratio de compactación sería especificar directamente el máximo número de objetos que pueden ser compactados en cada recolección de basura.
  4. Conocer el tamaño de los objetos: Conocer el tamaño de los objetos que la aplicación maneja también es importante. En un caso extremo, si se están almacenando objetos demasiado grandes, que no cojan en la young generation (e.g. enormes imágenes) irán directamente a parar a la old generation, incluso cuando se usen tan sólo temporalmente. En este caso, y si nuestra aplicación maneja frecuentemente este tipo de objetos, podemos caer en una situación en las recolecciones completas de basura sean muy frecuentes, o en la que simplemente obtengamos OutOfMemoryExceptions.

Bueno, más o menos estas son las cosillas que recogí en el análisis y que quizás a alguien le valgan. Dejo aquí unos enlaces con mucha más información y que he utilizado de fuente:

BEA JRockit configuration and tuning guide
BEA Memory Management Concepts Guide
IBM Garbage Collection Policies
Tuning Garbage Collection with the 5.0 Virtual Machine
Jon Masamitsu's Weblog

Si alguno tenéis alguna recomendación, añadido, corrección, etc., pues los comentarios son más que bien recibidos.

martes, julio 10, 2007

GC para tiempos bajos de respuesta (I)

martes, julio 10, 2007 por Martín

Hace unas semanas tuve que realizar un pequeño análisis de la recolección de basura en JRockit para llegar a una recomendacción de argumentos, políticas, etc. Voy a poner aquí algunas de las notas por si a alguno le resultan útiles, aunque la verdad es que muchos seguro que ya las conocéis de sobra.

Gran parte de este análisis está basado en la búsqueda de tiempos de respuesta bajos. En el caso de intentar optimizar un sistema para un máximo throughput, sería necesario realizar algunos cambios. Son notas genéricas en la medida de lo posible aunque mi análisis estaba orientado a JRockit.

  1. Preferir GC estático sobre dinámico: Algunas máquinas virtuales, como por ejemplo JRockit, tienen un modo de ejecución dinámico en la que van modificando los parámetros del algoritmo de recolección de basura en base al rendimiento de la aplicación. Son capaces de aumentar el tamaño del heap, disminuirlo, cambiar el tamaño de las generaciones o cambiar los valores de los diferentes parámetros según crean conveniente.

    El problema de esto es que con un algoritmo dinámico pierdes el control de la gestión de basura, y aunque la máquina virtual es realmente inteligente, en muchas ocasiones te desea restringir lo máximo posible la libertad del GC para tener la situación controlada.

    Este es el caso de los sistemas donde no se puede tolerar de ningún modo un tiempo de respuesta alto, ya que puede significar el incumplimiento de un SLA y como consecuencia una perdida económica importante.
  2. Establecer el máximo el mínimo del heap al mismo valor: De lo contrario, la máquina virtual estará gastando valiosos ciclos de CPU en alargar y encoger el tamaño del heap continuamente según considere conveniente. Nuevamente esto puede afectar al rendimiento de la aplicación e influir negativamente en los tiempos de respuesta.
  3. Asegurarse de que el tamaño del heap no es tan o más grande que la memoria física: En un servidor (o cualquier ordenador) siempre hay más procesos ejecutándose a parte de la máquina virtual. Estos procesos requerirán su espacio de memoria física. Si el tamaño del heap de la máquina virtual es demasiado grande entonces podemos caer una situación en la que nuestro servidor esté continuamente paginando porque no habrá suficiente memoria física para todos los procesos, o sólo para él si ha pedido demasiada memoria. Esto originará continuos accesos a memoria virtual para intercambiar páginas de memoria, lo que enlentecerá todo el sistema, disminuyendo drásticamente el rendimiento del mismo.
  4. Utilizar un algoritmo de recolección concurrente: Hoy por hoy la mayoría de máquinas virtuales te ofrecen la posibilidad de utilizar diferentes algoritmos según tus necesidades. Dos de los algoritmos más típicos son el concurrente, orientado a tiempos de respuesta bajos, y el paralelo orientado a conseguir un máximo throughput.

    En el algoritmo concurrente la recolección de basura se hace paralelamente a la ejecución de la aplicación, en pequeñas pausas que dan la impresión de que no hay recolección de basura. La desventaja es que se dedica constantemente tiempo de CPU para realizar esta labor.

    En un algoritmo paralelo, el recolector simplemente no realiza la recolección de basura hasta que no se llena por completo el heap. Una vez que el heap está completo, se para la ejecución de todos los hilos y se inicia una enorme recolección de basura dedicando todas las CPUs disponibles a esa tarea. Todas las CPUs realizan la recolección de modo paralelo.

    El problema de este último algoritmo para sistemas de respuesta baja es que la recolección puede ser enormemente costosa y detener el sistema por segundos o incluso minutos, lo que significa con toda seguridad romper SLAs que tengas marcados. Es por ello que un sistema como estos no puede recurrir a una recolección de este estilo que para por completo la ejecución del sistema.
  5. Optimizar el tamaño de la young generation:
  6. Los algoritmos orientados a una rápida respuesta suelen estar basados en generaciones. Normalmente hay dos generaciones, una joven (young generation, nursery en JRockit) en la que se alojan los objetos recientemente creados, y otra vieja (old generation) en la que se van guardando los objetos que permancen más tiempo en memoria. Las recolecciones de basura en la young generation suelen ser cortas y rápidas. Cuando la young generation se llena, se realiza una recolección, se vacia la generación y se mueven los objetos que deban quedar en memoria a la old generation. El tamaño de esta young generation es bastante importante. La idea es mantener su tamaño lo más grande que sea posible al tiempo que se mantiene el tiempo de recolección en un rango aceptable. Si la young generation es demasiado grande, las recolecciones serán más costosas y esto impactará en el rendimiento del sistema. Al mismo tiempo, estaremos dejando menos espacio disponible para la old generation, lo que eventualmente puede hacer que las recolecciones completas de todo el heap sean más frecuentes. Por el contrario, si el tamaño de la young generation es demasiado pequeño, no daremos tiempo a que los objetos se liberen, y la mayor parte serán promocionados rápidamente a la old generation, lo que hará que ésta última se llene rápidamente causando recolecciones completas de todo el heap. Es importante pues mantener el tamaño de la young generation en un punto equilibrado. Lo suficientemente grande para darle tiempo a los objetos a ser desreferenciados pero sin que sea demasiado costoso realizar una recolección de basura en ella.


Como he visto que este post me queda bastante largo he decidido dividirlo en dos. Muy pronto pondré la segunda parte. Mientras tanto si alguien quiere aportar algo... bievenenido sea.