Translate

lunes, junio 08, 2015

Variado, JAVA: Memoria, TImeZone y Parametros especiales

En Java, hay varios parámetros para controlar el tamaño inicial y el tamaño máximo que puede tomar la máquina virtual.
Además, hay que tener en cuenta el tipo de memoria sobre el que se quiere actuar: heapnon-heap (PermGen). Los valores por defecto que se dan corresponden a máquina virtuales de Sun, y son orientativos, porque pueden cambiar entre versiones de la máquina virtual. Los parámetros son los siguientes, fijándose a 128Mb.
  • -Xms128mTamaño de inicio de la máquina virtual de Java a 128Mb. El valor por defecto son 64Mb. Si se aumenta este valor, se elimina el tiempo que se tardaría en aumentar el tamaño en memoria de la máquina virtual si se llegara el caso de que se necesitara más memoria, por lo que aumentaría el rendimiento en los casos que la aplicación haga uso intensivo de la memoria.
  • -Xmx128mTamaño máximo de la máquina virtual de Java a 128Mb.  El valor por defecto son 128Mb. Si la aplicación supera el tamaño máximo de memoria que marca este parámetro, se lanza la excepción java.lang.OutOfMemoryError.  No conviene asignar a este parámetro el máximo de la memoria de la máquina porque si ya no queda memoria física disponible (por la que usa el sistema operativo u otras aplicaciones) se pueden producir escrituras en memoria asignada a otros programas y provocar un auténtico lío.
  • -XX:PermSize=128mTamaño de inicio de la memoria de tipo PermGen a 128Mb. Arrancar la máquina virtual con un valor superior al por defecto agiliza la carga de aplicaciones, sobre todo en el caso de aplicaciones que hagan uso intensivo de este tipo de memoria (Spring, Hibernate…)
  • -XX:MaxPermSize=128mTamaño máximo de la memoria de tipo PermGen a 128Mb. El valor por defecto son 64Mb. Si la aplicación supera el tamaño máximo de memoria para este tipo que marca este parámetro, se lanza la excepción java.lang.OutOfMemoryError: PermGen space. El valor necesario para este parámetro siempre suele ser menor que el de la memoria de tipo heap.
Si se quiere especificar un valor distinto de 128Mb, que se utiliza para todos los parámetros como ejemplo para simplificar, bastaría con sustituir el valor 128 del parámetro con el que se desee, siempre que sean múltiplos de 2 (64, 128, 256, 512, 768, 1024, 2048…)
Conocidos los tipos de memoria y los parámetros que los controlan, ahora viene la pregunta, ¿cómo especifico estos valores para mi aplicación? La respuesta es la misma para todos los casos: Los valores se especifican como parámetros en el arranque de la máquina virtual que ejecutará la aplicación. La diferencia estribará en cómo se arranca la aplicación: con un script, desde línea de comandos, mediante ant…
A continuación se dan distintos ejemplos de modificación de la memoria de distinta forma. No es necesario especificar todos los parámetros, se pueden especificar todos o ninguno (y se tomarían los valores por defecto)
Línea de comandos
  • Ejecución de un jar: java -Xms128m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m  -jar example.jar
  • Ejecución de una clase: java -Xms128m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m  com.programacionenjava.examples.MemoryExample
Script
Si el arranque de la máquina virtual se produce en un script, hay que editar el script y añadir estos parámetros en la sentencia de arranque. El siguiente ejemplo muestra cómo añadir estos parámetros en el script de arranque de un Tomcat/JBOSS.
  • En Windows: set JAVA_OPTS=%JAVA_OPTS% -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=256m
  • En Linux: JAVA_OPTS=”$JAVA_OPTS -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=256m”
Por último, recordamos que resolver el problema de una excepción de tipo java.lang.OutOfMemoryError simplemente aumentando el tamaño de la memoria virtual puede retrasar el problema pero no evitarlo si el problema es una fuga de memoria. 

Ajustar el timezone de Java en Linux


Si en alguna de tus aplicaciones te ha ocurrido que la api deJava (Date o GregorianCalendarno te da la hora correctamente, aún siendo correcta la del sistema operativo, probablemente se deba a que Java no está interpretando la zona horaria correctamente.

Me sucedió en mi Debian, y lo primero que se me ocurrió fue ajustar el timezone del sistema operativo con el comando tzconfig. Efectivamente, la zona horaria no estaba configurada correctamente, pero aún corrigiendo esto la hora de Java seguía sin ser la correcta. 

En concreto mi zona horaria era GTM+2, correspondiente a España en verano, mientras que laJVM me daba GTM+1. En ese momento lo consideré una chorrada. Además el cambio horario estaba cerca y el problema desaparecería al pasar al horario de invierno (GTM+1) :-p. Ha sido hoy cuando la chorrada ha pasado a ser un problema y por ello no he tenido más remedio que buscar la solución.

La solución es bien sencilla

Probablemente ya la sepas, pero soy de los que piensa que más vale encontrar algo útil un millón de veces a no encontrarlo nunca.

Hay tres soluciones posibles:

  1. Ajustar la variable de entorno TZ.

    bash$ export TZ="Europe/Madrid"

  2. Incluir el parámetro -Duser.timezone en la ejecución del comando java.

    bash$ java -Duser.timezone=Europe/Madrid ...."

  3. Ajustar el fichero /etc/localtime para que apunte a la zona horaria correcta. Todas las zonas horarias disponibles se encuentran en /usr/share/zoneinfo.

    bash$ ln -s /usr/share/zoneinfo/Europe/Madrid /etc/localtime

Puedes tomar la solución que veas más conveniente, pero si no eres el administrador de la máquina, probablemente la tercera solución te sea imposible.

Parámetros variados pasadas a JAVA a la hora de arrancar JBOSS/TOMCAT:

-Dsun.rmi.dgc.client.gcInterval=3600000: Es necesario para asegurar que la DGC realiza llamadas limpias a referencias remotas y dichas llamdas se entregan en el momento oportuno , el valor de esta propiedad representa el intervalo máximo ( en milisegundos ) que el tiempo de ejecución de Java RMI permitirá entre las colecciones de basura en la memoria HEAP. . El valor predeterminado es 3600000 milisegundos (una hora) .
-Dsun.rmi.dgc.server.gcInterval=3600000:  Es necesario para asegurar que los objetos remotos que ya no valen son recolectados como  basura en el momento oportuno , el valor de esta propiedad representa el intervalo máximo ( en milisegundos ) que el tiempo de ejecución de Java RMI permitirá recolectar dicha basura en la memoria HEAP . El valor predeterminado es 3600000 milisegundos (una hora) .
-Dcom.sun.management.jmxremote:  Habilita la monitorización remota bajo la JMXConsole.
-Duser.language=es: Parámetro Locate, para usar la ISO adecuada a nuestra instalación

No hay comentarios: