La extracción de información útil de sus archivos de registro es fundamental para el éxito de su aplicación Java. Los datos de registro le darán una valiosa información sobre el rendimiento, la estabilidad y la usabilidad de su aplicación.

El análisis de los datos de registro puede parecer tedioso, pero no tiene por qué serlo. Hay una variedad de herramientas para leer, analizar y consolidar los datos de registro. Las herramientas básicas de línea de comandos como grep, uniq y sort pueden combinar y extraer información útil de los archivos de registro. Los analizadores de registros más avanzados, como Logstash o Fluentd, pueden extraer datos clave de los registros y convertirlos en tokens de fácil búsqueda. Los servicios de registro basados en la nube, como SolarWinds® Loggly®, almacenan sus datos de registro por usted y ofrecen sofisticadas capacidades de análisis, eliminando la necesidad de mantener los registros usted mismo.

Esta sección explora algunos métodos y herramientas para analizar los registros con el objetivo de mejorar sus aplicaciones.

Encontrar las excepciones más comunes

Encontrar las excepciones más comunes puede ayudarle a identificar las áreas de bajo rendimiento en su aplicación Java. La mayoría de los marcos de registro registran el tipo de excepción, el mensaje de excepción y el método en el que se produjo la excepción. Usando Log4j, un registro de excepciones tendrá un aspecto similar a uno de los siguientes.

09:54:44.565 ERROR Log4jTest.MathClass - java.lang.ArithmeticException: / by zero10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: myFile (No such file or directory)10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: newFile (No such file or directory)

Si su salida incluye trazas de pila, vea la sección Parsing Multiline Stack Traces de esta guía.

Comencemos con un ejemplo sencillo usando la popular herramienta GNU grep. Luego, mostraremos cómo una herramienta de gestión de registros puede hacerlo aún más fácil.

Encontrar excepciones por tipo usando grep

El siguiente comando de Unix encontrará excepciones, extraerá el tipo de excepción y contará el número de ocurrencias. grep es una popular herramienta de línea de comandos que realiza la coincidencia de patrones, mientras que uniq y sort agrupan y ordenan los resultados, respectivamente:

$ grep -o "\w*Exception" myLog.log | sort -r | uniq -c

En este ejemplo, la expresión regular \w*Exception coincide con cualquier palabra que termine con «Exception.» La bandera -o indica a grep que imprima sólo las partes de la salida que coinciden con la cadena de búsqueda. sort -r ordena el resultado en orden inverso, mientras que uniq -c agrupa los resultados y cuenta el número de ocurrencias. Como resultado, terminamos con un conteo de excepciones por tipo.

2 FileNotFoundException1 ArithmeticException

También podemos usar grep para buscar en el registro cada instancia específica de estas excepciones.

$ grep ArithmeticException myLog.log09:54:44.565 ERROR Log4jTest.Log4jTest - java.lang.ArithmeticException: / by zero

Esto devuelve cada línea que contenga una instancia de la cadena de búsqueda ArithmeticException, con la propia cadena de búsqueda resaltada en la salida.

Encontrando excepciones por clase usando grep

También puede buscar excepciones por la clase en la que ocurrieron. Para los eventos de registro de una sola línea, el siguiente comando agrupa el número de excepciones por clase y por tipo. grep extrae el nombre de la clase buscando una palabra seguida de un carácter concreto (en este ejemplo se utiliza un guión, aunque se puede utilizar cualquier carácter siempre que sea único para la entrada). Aunque este carácter no es esencial, nos ayuda a localizar el nombre de la clase en el evento de registro. Con el operador OR (denotado por |), grep también extraerá el nombre de la excepción buscando una palabra que contenga la cadena «Exception».»

sed es otra utilidad de línea de comandos que puede utilizarse para formatear la salida de grep. En este ejemplo, sed elimina el carácter especial de nuestra salida, así como cualquier carácter de nueva línea. A continuación, la salida se canaliza a los comandos uniq y sort para agrupar y ordenar los resultados respectivamente.

$ grep -o "w* -|\w*Exception" myLog.log | sed 'N; s/ -n/ /' | sort -r | uniq -c

El resultado nos acerca a las áreas de problemas clave:

2 Log4jTest FileNotFoundException1 MathClass ArithmeticException

Con estos resultados, podemos utilizar grep para encontrar más detalles sobre los problemas que se producen en clases específicas. Por ejemplo, el siguiente comando recupera las excepciones que se produjeron en la clase MathClass.

$ grep -e "MathClass.*Exception" myLog.log09:54:44.565 ERROR Log4jtest.MathClass - java.lang.ArithmeticException: / by zero

Usando una solución de gestión de registros

La mayoría de las soluciones de gestión de registros ofrecen formas de agrupar y buscar entradas de registro basadas en el tipo de registro, el contenido del mensaje, la clase, el método y el hilo. Si sus registros ya están siendo analizados y almacenados, muchas soluciones pueden graficar y ordenar las excepciones por el número de ocurrencias. Esto es una operación de apuntar y hacer clic en Loggly, por lo que no es necesario memorizar complicados comandos grep. Loggly también indexa los registros de la bitácora, haciendo que las búsquedas y los recuentos sean mucho más rápidos que con grep. Por ejemplo, podemos utilizar el explorador de campos para ver una lista de excepciones y su frecuencia, y luego hacer clic en una excepción para ver todos los registros relevantes.

Usando el explorador de campos de Loggly para encontrar rápidamente registros por tipo de excepción.

Loggly también ofrece herramientas de visualización que pueden ser más informativas que la salida basada en texto de grep. Gráficos como este pueden ayudarle a priorizar los recursos para los sprints de desarrollo o para los parches después de una nueva versión.

Gráfica de excepciones por frecuencia en Loggly.

Depuración de problemas de producción

Cuando se trata de problemas de producción, el tiempo es esencial. Un error crítico en su aplicación no sólo dejará a sus usuarios descontentos; también bajará las ventas y reducirá la confianza en su aplicación o servicio.

En la mayoría de los casos, la resolución de un problema puede dividirse en tres pasos clave:

  1. Recoger información sobre el problema
  2. Identificar la causa del problema
  3. Encontrar una solución y evitar que el problema se repita

Recoger información sobre el problema

El primer paso es recoger información sobre el problema. Reúna toda la información posible -capturas de pantalla, informes de fallos, registros, enlaces (para servicios web), etc.- para ayudar a reducir las posibles causas. Querrá que el usuario que experimentó el problema proporcione información detallada sobre el evento, incluyendo: cuándo y en qué parte del programa ocurrió el problema, sus acciones que condujeron al problema, el entorno operativo y cualquier comportamiento extraño o inusual del programa antes y después de que ocurriera el problema.

A partir de ahí, puede comenzar a recopilar información de registro. Si su aplicación es un servicio alojado, comience a recuperar los registros de los servidores web y de aplicaciones. Si su aplicación es un paquete de software distribuido, pida al usuario que incluya los datos de registro en su informe de errores. Alternativamente, si su aplicación envía eventos de registro a un servidor de registro centralizado, entonces sus registros estarán disponibles inmediatamente.

Una vez que tenga una cantidad razonable de datos sobre el problema, puede empezar a rastrearlo en el código.

Identificar la causa del problema

Después de recoger información sobre el problema, el siguiente paso es identificar su causa. Reproducir un error en un entorno de desarrollo es una de las formas más sencillas de validar su existencia, pero puede llevar mucho tiempo y puede no funcionar en todos los casos. Disponer de un conjunto completo de registros le llevará directamente al origen del problema, ahorrándole tiempo y frustración.

Un informe de errores le dará una idea general de cuál es el problema y dónde se ha producido. Utilizando la herramienta de gestión de registros de su elección, puede limitar su búsqueda a un rango más pequeño de entradas de registro mediante la búsqueda de un token de datos único, como un nombre de usuario, un ID de sesión o un texto de mensaje.

Vamos a recorrer un escenario de ejemplo para demostrar cómo depurar un sistema. Imaginemos que tenemos una interfaz basada en la web para iniciar sesión de forma remota en un sitio web. La página web tiene una pantalla de inicio de sesión que realiza la autenticación básica utilizando un nombre de usuario y una contraseña. Los usuarios han informado de que no pueden iniciar sesión en el sitio web. La página web acepta su entrada pero luego falla con un error genérico.

Un ejemplo de sitio web que informa de un error después de un intento de inicio de sesión.

Este mensaje no nos da mucha información aparte de una indicación genérica de la gravedad del registro. Buscar en un gestor de registros las entradas con «Severo» en el nivel o el mensaje podría dar lugar a cientos de resultados sin garantía de que ninguno de ellos esté relacionado con el problema en cuestión. Afortunadamente, nuestro Logger también registró el nombre de usuario que experimentó el error, por lo que podemos filtrar en el nombre de usuario «admin».

Ver una excepción de Java en Loggly.

Si profundizamos, vemos que la causa del error es una tabla faltante o inválida. Este es un problema grave, ya que podría indicar un borrado accidental o la corrupción de la base de datos.

ERROR: Exception for user admincom.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test_schema.users' doesn't exist...com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1651) at TestApplication.Test.doPost(Test.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at...

Mirando a través del seguimiento de la pila, vemos que el servicio falló en la línea 33 de Test.java. Esta línea consiste en una sentencia SQL que extrae datos sobre un usuario de la tabla test_schema.users.

rs = stmt.executeQuery("SELECT * FROM test_schema.users WHERE username = " + username + " AND Password = " + password);

Cuando intentamos ejecutar esta consulta en un front end SQL, encontramos que la tabla «test_schema.users» no existe. Sin embargo, la base de datos sí tiene una tabla «test_schema.user». En algún momento, un desarrollador podría haber escrito por error el nombre de la tabla equivocado y haber pasado el formulario revisado a producción. Ahora sabemos cuál es el problema y dónde aparece en nuestro código.

Usando SolarWinds Loggly, puede depurar y encontrar la causa raíz de los problemas rastreando los errores a través de la pila de su aplicación, a través de múltiples eventos de registro, e incluso señalando la línea de código relevante en GitHub.

Resolver el problema y evitar que se repita

Ahora que hemos identificado el problema y su causa, el paso final es arreglarlo. Nuestro ejemplo de inicio de sesión fue un caso exagerado con una solución relativamente fácil, pero usted puede encontrarse con errores más complicados arraigados en diferentes áreas de su aplicación. Antes de lanzarse a la solución rápida y sucia, considere cuidadosamente cómo su cambio afectará a la aplicación. ¿Es realmente la mejor solución para el problema? ¿Es posible que el cambio interfiera con otro componente? ¿Esta solución dificultará la introducción de nuevas correcciones o características en el futuro? ¿Evitará esta solución que surjan problemas similares más adelante?

Por ejemplo, ¿qué pasa si dos usuarios diferentes consiguen crear dos cuentas distintas con el mismo nombre de usuario y contraseña? Podría imponer un nombre de usuario único para todos los usuarios, pero ¿cómo afectaría eso a la estructura de su base de datos, a su código de autenticación y a su base de usuarios existente? Podrías añadir un nuevo campo único, como una dirección de correo electrónico, y hacerlo obligatorio, pero ¿qué pasa si algunos de tus usuarios actuales no han proporcionado direcciones de correo electrónico? ¿Y si algunas direcciones de correo electrónico se comparten entre varias cuentas? ¿Cómo afectarán estas nuevas reglas a las páginas de registro, búsqueda y administración? En un entorno empresarial, su código tendrá que ser revisado por otros desarrolladores, integrado en la base de código, construido, probado por el departamento de control de calidad, puesto en escena, y tal vez pasar por varios pasos más antes de llegar a la producción. Su empresa puede tener protocolos específicos para los errores críticos o sensibles al tiempo que debe seguir. Una vez que hayas encontrado una solución, incluye tu resolución en la documentación, así como cualquier solución razonable para el problema. De esta manera, sus clientes pueden seguir utilizando su producto y su equipo de soporte puede reducir el número de informes de errores duplicados mientras la solución llega a producción.

Después de desplegar la solución, continúe supervisando su aplicación de producción para verificar que el problema se ha resuelto. Por ejemplo, después de desplegar la corrección del problema de la base de datos en el ejemplo anterior, ya no deberíamos ver eventos con «La tabla ‘test_schema.users’ no existe». Si los errores continúan o si empezamos a ver nuevos errores, sabemos que la corrección no ha funcionado. En el mejor de los casos, veremos un patrón como el que se muestra en la siguiente captura de pantalla, en la que el número de errores cae a cero inmediatamente después de desplegar el parche.

Gráfica del número de registros que contienen un error en Loggly.

Más herramientas de depuración de producción

Aunque el registro es el método probado y verdadero para la solución de problemas y la depuración de aplicaciones, estas herramientas pueden ayudarle a obtener más información sobre el funcionamiento de su aplicación.

jdb

jdb, el depurador de Java, es una utilidad de línea de comandos para la depuración de clases de Java. jdb es fácil de usar y viene incluido en el kit de desarrollo de Java. El uso de jdb crea una nueva máquina virtual de Java (JVM), lo que le permite depurar una clase sin afectar a ningún programa en ejecución. También puede utilizar jdb para depurar aplicaciones en ejecución añadiendo los siguientes parámetros a su comando java:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n

Cuando la JVM se inicia, asigna un número de puerto para las conexiones jdb entrantes. A continuación, puede adjuntar a la instancia JVM en ejecución utilizando jdb -attach:

$ jdb -attach

Puede utilizar esto, por ejemplo, para conectar su depurador a una instancia de producción en ejecución. Tenga cuidado con el uso de puntos de interrupción en este escenario, ya que podría pausar un hilo activo. Esto puede tener consecuencias si, por ejemplo, un cliente está usando la aplicación mientras la estás depurando. Para más información, consulte la documentación de Java sobre jdb.

OverOps

OverOps es un conjunto de herramientas para monitorizar aplicaciones, analizar el código y detectar problemas. A diferencia del software de registro, que se basa en la salida generada por una aplicación en ejecución, OverOps se conecta directamente a la máquina virtual de Java para trazar la base de código de la aplicación, leer variables y registrar errores. Esto le permite detectar más errores y registrar más datos que incluso el marco de registro de la aplicación. OverOps utiliza un modelo de software como servicio (SaaS), en el que las métricas se recogen y almacenan en los servidores en la nube de OverOps. Sin embargo, también se puede implementar en las instalaciones. En cualquier caso, puede ver sus datos utilizando una interfaz basada en la web.

BTrace

BTrace es una herramienta de trazado que le permite supervisar todos los aspectos de su aplicación, desde los nombres de las clases hasta los errores. BTrace utiliza un enfoque de programación orientado a aspectos que implica el uso de anotaciones, que especifican dónde y cómo BTrace monitoriza su aplicación. Por ejemplo, el siguiente script de BTrace monitoriza y registra todas y cada una de las llamadas al paquete javax.swing.

import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*; @BTrace public class AllMethods { @OnMethod( clazz="/javax\.swing\..*/", method="/.*/" ) public static void m(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod) { print(Strings.strcat("entered ", probeClass)); println(Strings.strcat(".", probeMethod)); }}

Para más información sobre BTrace, consulte el repositorio GitHub y el Wiki de BTrace.

Chronon

Chronon permite rebobinar y reproducir todo el flujo de ejecución de una aplicación. Registra cada cambio individual realizado durante la vida de una aplicación, permitiéndole reproducir el estado de la aplicación en cualquier momento. Las grabaciones se guardan en un archivo, lo que facilita la transferencia del historial de ejecución desde una máquina de producción a una máquina de desarrollo para realizar pruebas.

Chronon está compuesto por el Chronon Recording Server, que permite grabar aplicaciones Java de forma remota; Embedded Chronon, que incorpora la grabadora dentro de una aplicación; y el Time Travelling Debugger, que permite reproducir las grabaciones.

jhsdb

jhsdb (Java HotSpot Debugger) es un conjunto de herramientas para depurar, analizar y perfilar la JVM por defecto proporcionada tanto con OpenJDK como con el JDK de Oracle. jhsdb le permite adjuntar a los procesos Java en ejecución, tomar instantáneas de los rastros de pila, e incluso analizar las JVMs colapsadas. Puede utilizarlo para acceder al montón, a la caché de código, a las estadísticas de recolección de basura y mucho más. Para obtener más información, consulte la página de documentación de jhsdb.

Tracing Transactions

Cuando se produce un problema, es importante saber dónde comenzó el problema y cómo afectó al resto de su aplicación. Esto es bastante difícil en una aplicación monolítica, pero se vuelve aún más difícil en una arquitectura orientada a servicios distribuidos, donde una sola solicitud puede afectar a docenas de servicios. No siempre es obvio qué servicio contiene la causa del error, o cómo ha afectado a otros servicios. El rastreo proporciona los datos necesarios para seguir la ruta de ejecución de su aplicación y profundizar en la causa exacta de un problema.

En la sección de depuración de problemas de producción de la guía, recorrimos un ejemplo en el que un usuario tenía dificultades para iniciar sesión en una aplicación web debido a una tabla de base de datos no válida. En esta sección, mostraremos cómo el rastreo de transacciones jugó un papel central en la resolución del problema.

Rastreo de IDs Únicos

Para rastrear una secuencia de eventos de registro, se necesita alguna forma de identificar de manera única los registros relacionados. Un entorno multiusuario podría generar cientos de registros idénticos, lo que dificulta la búsqueda basada en la marca de tiempo o Logger. Una solución más fácil es incluir un identificador único con las entradas de registro relacionadas. Este identificador podría ser un nombre de usuario, un ID de sesión, una clave API o un Identificador Único Universal (UUID). Afortunadamente, ThreadContext es perfectamente adecuado para este trabajo.

En el ejemplo de depuración de problemas de producción, teníamos una interfaz de usuario basada en la web que estaba alojada en un servlet Tomcat, que se conectaba a una base de datos MySQL. Los usuarios introducían sus credenciales en la página web y, tras pulsar enviar, el servlet ejecutaba una consulta comparando sus credenciales con las almacenadas en la base de datos. Si el usuario se autenticaba con éxito, se le redirigía a la página principal. Si se producía un error, se registraban los detalles del mismo y se presentaba a los usuarios un mensaje genérico.

Pudimos depurar este problema incluyendo los nombres de usuario de los usuarios en el mensaje de registro. Esto nos permitió buscar rápidamente los eventos de registro relacionados con el usuario administrador. Basándonos en este mismo ejemplo, podemos utilizar ThreadContext.put() para asignar un nombre de usuario a un Logger. Cuando los usuarios envían sus credenciales, el servlet entra en el método doPost(), que añade los nombres de usuario de los usuarios al ThreadContext:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {ThreadContext.put("username", request.getParameter("username"));logger.info("Entering doPost().");...}

Usando Log4j con el patrón %p : %m%n se obtiene la siguiente entrada:

INFO : Entering doPost().

Podemos añadir eventos similares para acceder a la base de datos MySQL, salir del método doPost, y realizar otras acciones. De esta manera, si el usuario desencadena una excepción, sabemos exactamente lo que el usuario estaba haciendo cuando ocurrió la excepción.

Tracing Method Calls

Muchos frameworks de registro proporcionan métodos nativos para trazar la ruta de ejecución de una aplicación. Estos métodos varían ligeramente entre los marcos, pero siguen el mismo formato general.

  • traceEntry() marca el comienzo de un método.
  • traceExit() marca el final de un método. Para los métodos que devuelven un objeto, puede devolver simultáneamente el objeto y registrar el evento con return logger.exit(object).
  • throwing() marca una excepción que es poco probable que se maneje, como un RuntimeException.
  • catching() marca una excepción que no se va a volver a lanzar.

Puede encontrar información específica del marco de trabajo sobre estos métodos en la documentación de Logger para Log4j, Logback y java.util.logging.

Métodos de trazado en Log4j

Como ejemplo de uso de Log4j, sustituiremos los métodos Logger.info() de nuestro servlet por métodos de trazado.

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { logger.entry(); ... logger.exit();}

También cambiaremos el Appender's PatternLayout para mostrar el nombre de la clase, el método y el número de línea (los patrones de conversión %class, %M y %line).

<PatternLayout pattern="%p %class %M %line: %m%n" />

Los métodos de trazado registran los eventos en el nivel TRACE, lo que significa que tendremos que cambiar el nivel Logger's de DEBUG a TRACE. De lo contrario, los mensajes de registro serán suprimidos.

<Loggers> <Root level="trace"> <AppenderRef ref="Console"/> </Root></Loggers> TRACE DatabaseApplication.Login doPost 26: entry...TRACE DatabaseApplication.Login doPost 59: exit

Los métodos de seguimiento también proporcionan su propioMarkers. Por ejemplo, los métodosLogger.entry()yLogger.exit()muestranENTERyEXITrespectivamente.

ENTER 14:47:41.074 TRACE DatabaseApplication.Login - EnterEXIT 14:47:41.251 TRACE DatabaseApplication.Login - Exit

Métodos de seguimiento en SLF4J

Los usuarios de SLF4J pueden aprovechar MDC para rastrear eventos de registro. De forma similar a Log4j, los valores MDC pueden utilizarse con un Appender utilizando el patrón de conversión %X.

SLF4J también proporciona métodos entry(), exit(), throwing() y catching() a través de la clase XLogger (Extended Logger). Puede crear una instancia de XLogger utilizando XLoggerFactory.getXLogger().

package DatabaseApplication;import org.slf4j.Logger;import org.slf4j.LoggerFactory; import org.slf4j.ext.XLogger;import org.slf4j.ext.XLoggerFactory; public class Login extends HTTPServlet { final static XLogger xlogger = XLoggerFactory.getXLogger(Login.class.getName()); final static Logger logger = LoggerFactory.getLogger(Login.class.getName()); @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { xlogger.entry(); .. xlogger.exit(); }}

Añada los patrones de conversión %class y %line a logback.xml.

<configuration> <appender name="Console" class="ch.qos.Logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %class{36} %M %L: %msg%xEx%n</pattern> </encoder> </appender> <root level="trace"> ... </root></configuration>

Las entradas de registro resultantes son idénticas a las creadas por Log4j.

Gestión del uso de la memoria

La gestión de la memoria a menudo se pasa por alto en lenguajes de alto nivel como Java. Mientras que la cantidad media de memoria en los dispositivos modernos es cada vez mayor, el alto uso de la memoria puede tener un gran impacto en la estabilidad y el rendimiento de su aplicación. Una vez que la máquina virtual de Java no puede asignar más memoria del sistema operativo, su programa podría terminar y bloquearse. Saber cómo gestionar la memoria evitará problemas a medida que su aplicación crezca en tamaño.

Por ejemplo, imaginemos que queremos almacenar un conjunto de números empezando por el uno. Un usuario proporciona un límite superior y el programa almacena cada número entero desde el «1» hasta ese límite. Utilizaremos un bucle while con un contador para añadir cada número a un array.

import java.util.Scanner;...System.out.print("Please enter the maximum size of the array: ");Scanner scanner = new Scanner(System.in);int limit = scanner.nextInt(); ArrayList intArray = new ArrayList(); int count = 1;while (count <= limit) { intArray.add(count);}

Habrás notado que count no se incrementa en el bucle. Esto es un gran problema; si el usuario introduce cualquier número mayor que cero, el array seguirá creciendo hasta que la JVM utilice toda su memoria disponible y el programa se cuelgue.

Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:2245)at java.util.Arrays.copyOf(Arrays.java:2219)at java.util.ArrayList.grow(ArrayList.java:242)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)at java.util.ArrayList.add(ArrayList.java:440)at MemoryTest.main(MemoryTest.java:10)

Recogida de basura

Para reducir el uso de la memoria, la máquina virtual de Java realiza un proceso periódico de limpieza conocido como recogida de basura. La recolección de basura busca bloques de memoria que ya no están en uso y los hace disponibles para su reutilización. Los siguientes recursos explican el proceso de recolección de basura de Java en mayor detalle.

  • Conceptos básicos de la recolección de basura de Java (Oracle)
  • Guía de ajuste de la recolección de basura de la máquina virtual HotSpot (Oracle)
  • Entender los registros de GC G1 (Poonam Bajaj)
  • Guía de ajuste de la recolección de basura (Atlassian)

El recolector de basura genera información de diagnóstico que puede ser útil para perfilar el rendimiento de las aplicaciones. Puedes registrar esta información pasando -Xlog:gc a la JVM al iniciar tu aplicación. Después de cada ejecución, el recolector de basura imprime estadísticas sobre el proceso de recolección de basura en el formato de registro unificado de la JVM. Aquí hay un ejemplo.

 Using G1 Periodic GC disabled GC(0) Pause Young (Normal) (G1 Evacuation Pause) 7M->1M(64M) 8.450ms

Using G1 dice qué método de recolección de basura se está utilizando. El recolector Garbage-First (G1) suele estar activado por defecto en ordenadores multiprocesadores con grandes cantidades de RAM. Periodic GC disabled indica que el proceso de recolección de basura no se repetirá. La tercera línea nos indica que se trata de una Pausa de Evacuación, en la que los objetos se copian entre regiones de memoria en función de si todavía están en uso. Pause Young nos dice que el proceso limpió la generación joven, que es donde se asignan los nuevos objetos. Como resultado, el uso total de memoria por parte de los objetos en la generación joven bajó de 7M a 1M de los 64M asignados, y el proceso tomó 8.450ms.

Con el recolector de basura imprimiendo información de diagnóstico en la consola, podemos ver cómo la cantidad de memoria asignada (el tamaño de la pila) continúa creciendo con el tiempo. Eliminaremos los tiempos de la CPU para simplificar.

$ java -Xlog:gc MemoryLeakDemo Using G1 Periodic GC disabled GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 25M->23M(64M) 4.372ms GC(1) Concurrent Cycle GC(1) Pause Remark 50M->34M(64M) 0.250ms GC(1) Pause Cleanup 94M->94M(124M) 0.057ms GC(1) Concurrent Cycle 169.695ms GC(2) Pause Young (Concurrent Start) (G1 Humongous Allocation) 94M->94M(124M) 3.738ms GC(3) Concurrent Cycle...

Gráfico que muestra un aumento gradual del uso del heap de la JVM a lo largo del tiempo.

Puedes añadir marcas de tiempo a cada entrada con -XX:+PrintGCDateStamps y -XX:+PrintGCTimeStamps. También puede registrar la salida del recolector de basura en un archivo pasando Xlog:gc:file: a la JVM cuando inicie su aplicación.

Si monitorea sus archivos de registro con rsyslog, puede enviar los registros a un sistema de registro centralizado donde serán analizados y estarán listos para un análisis casi en tiempo real. Este es el aspecto de un gráfico de línea de tiempo en Loggly. Muestra el tamaño total de la pila, así como el tamaño de la pila antes y después de que se ejecute el recolector de basura.

Fugas de memoria

Una fuga de memoria es una situación en la que un programa asigna memoria más rápido de lo que puede liberarla. La forma más fácil de detectar una fuga de memoria es cuando su programa deja de responder, se vuelve inestable o causa OutOfMemoryErrors. En Java, encontrará más casos de colecciones Full GC a medida que aumenta el uso de la memoria.

Puede obtener más información sobre la salida del recolector de basura y la localización de fugas de memoria en el capítulo Solución de problemas de fugas de memoria de la documentación de Java.

Recursos adicionales

Reduzca el tiempo de depuración sin escribir una sola línea de código (Loggly)-Guía para utilizar Takipi

La guía definitiva: 5 Methods for Debugging Production Servers at Scale (High Scalability)-Herramientas y técnicas para depurar problemas de producción

Memory Management

Garbage Collection Tuning Guide (Oracle)-Guía para entender y afinar la recolección de basura de Java

Understanding Java Garbage Collection (CUBRID Blog)-Guía para garb

See it. Analícelo. Inspeccionarlo. Resuélvelo

Ve lo que importa.

COMENZAR PRUEBA GRATIS

Deja una respuesta

Tu dirección de correo electrónico no será publicada.