1. Lo básico: versión de JVM, modo de ejecución y tamaño de heap de Java
El contenedor web esta configurado con los siguientes parámetros para el catalina_opts /apache-tomcat-6,0,16/bin/catalina.sh-Xms1024
-Xmx1024
-Xmn512
-XX:PermSize=128
-XX:MaxPermSize=512
2. Tuning del recolector de basura: hilos de ejecución
Por default, el número de hilos de ejecución asignados al GC son equivalentes al número de threads disponibles en el procesador. Sin embargo, esto puede ser muy ineficiente en sistemas con una buena cantidad de multithreading, siendo de 1/2 a 1 la proporción aconsejable.-XX:ParallelGCThreads=6
3. Tuning del recolector de basura: incrementando la generación joven
Cuando se ejecuta un programa en Java, todos los objetos que se van creando pertenecen a tres generaciones, como se muestra en el siguiente esquema:Las tres generaciones de objetos en Java. (Fuente: java.sun.com) Cuando se crea un objeto nuevo en Java con la instrucción new, éste inicialmente se encuentra en el espacio Edén (Eden space). Conforme se van ejecutando varios ciclos de recolección de basura o se van creando nuevos objetos, éstos van migrando a través de “espacios de supervivencia” (Survivor spaces) al ser copiados sobre áreas menos transaccionales de la memoria. La región tenured es la más importante pues en ésta se genera la mayoría de las operaciones en Java. Finalmente, aquellos objetos que han permanecido activos por mucho tiempo pasan a formar parte del espacio permanente (perm space) pues difícilmente serán eliminados.
Así entonces, en un ambiente altamente transaccional, es conveniente que entre el 6 y el 12% de la pila de memoria sea parte de la generación joven, pues se están creando muchos objetos en Java que serán migrados rápidamente. El tamaño por default es de apenas 2 MB y puede crecer de manera ilimitada, quemándose todo el espacio dedicado al tenured o perm, por lo que siempre es conveniente definir su tamaño explícitamente:
-XX:MaxNewSize=64m
-XX:NewSize=64m
4. Tuning del recolector de basura: corriendo en paralelo
Por default, el Garbage Collector de la máquina virtual de Java usa el modo “serial” de recolección, pero esto sólo sirve en máquinas con un solo CPU. Para servidores de aplicaciones con 2 o más cores, tenemos la dos opciones (modos) :El Modo paralelo
-XX:+UseParallelGC
modalidad de “pequeños impulsos frecuentes”. Esta opción disminuye un poco el rendimiento del sistema a cambio de no congelar la aplicación cada que se llena el GC.
-XX:+UseConcMarkSweepGC
ó -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
5. Tuning del recolector de basura: incrementando la generación permanente
Así como estamos definiendo un tamaño para la generación joven, también es posible definir uno para el espacio permanente (perm space) que en aplicaciones con muchos objetos estáticos y utilerías (sobre todo en Ajax) pueden generar el temido java.lang.OutOfMemoryError: PermGen space. Cabe destacar que si estamos encontrando constantemente errores de este tipo aunque incrementemos el espacio considerablemente (>25% del espacio asignado al heap), significa que tenemos un problema de objetos no recolectados que requiere echarse un clavado en el código.-XX:MaxPermSize=128m
6. Paginación de la memoria
El objetivo de la paginación en Java es optimizar los búferes de traducción y búsqueda en memoria (Translation-Lookaside Buffers – TLB). Estos son en pocas palabras, caches que almacenan los últimos mapeos de memoria virtual a física. Modificando los valores correspondientes se incrementa la eficiencia del uso memoria. En la mayoría de los casos no se recomienda pasar de 6 MB de paginación pues puede ser contraproducente.-XX:+UseLargePages
-XX:LargePageSizeInBytes=5m
7. Non-Uniform Memory Architecture (NUMA)
Debido a que una buena parte de las arquitecturas multiprocesador están basadas en el uso de memoria de acuerdo a posiciones relativas a otro procesador o a través de memoria compartida entre procesadores, es posible utilizar una opción de “escopetazo” denominada NUMA. El uso de este parámetro en combinación con -XX:+UseParallelGC puede incrementar significativamente el desempeño:-XX:+UseParallelGC
-XX:+UseNUMA
8. Tuning del recolector de basura: pasando de generación
en generación El parámetro -XX:SurvivorRatio puede utilizarse para ajustar el tamaño de los espacios de supervivencia. Aunque no es tan importante para el rendimiento, sí permite ayudarnos a definir cuál será el espacio para el resto de las generaciones, pues si son demasiado pequeños, los nuevos objetos serán copiados directamente en el espacio tenured y si son demasiado grandes, se está desperdiciando memoria. Por ejemplo, -XX:SurvivorRatio=6 significa que existirá una relación de 6 a 1 entre el Edén y los survivor spaces.Por otro lado, la JVM define por defecto un “porcentaje de ocupación” del 50% del survivor space actual para empezar a copiar los objetos que contiene al siguiente espacio. Esto puede significar un desperdicio del 50% de la memoria designada a los survivor spaces, por lo que conviene incrementarla para hacer un uso más eficiente de la misma. -XX:TargetSurvivorRatio permite definir el porcentaje de uso necesario para copiar los objetos del actual espacio al siguiente:
-XX:SurvivorRatio=8
-XX:TargetSurvivorRatio=90