Introducción
Utilizando una aplicación Java, a menudo nos enfrentamos a problemas relacionados con el consumo de memoria. Generalmente, podemos categorizar todos los problemas en aquellos relacionados con el uso de memoria heap y aquellos basados en el uso de memoria no-heap. En este artículo, revisaremos diferentes herramientas que podemos utilizar para monitorear la utilización de memoria no-heap.
La memoria no-heap incluye varias secciones importantes que son críticas para el rendimiento de nuestras aplicaciones. Si deseas garantizar que tu aplicación Java funcione con eficiencia máxima, necesitarás saber cómo evaluar y optimizar el uso de esta memoria. A lo largo de este artículo, exploraremos las herramientas disponibles, cómo usarlas y ejemplos prácticos para facilitar su implementación en proyectos reales.
1. Overview
Java, siendo un lenguaje de programación robusto, proporciona varias herramientas incorporadas y de terceros para ayudar a los desarrolladores a controlar la memoria utilizada por sus aplicaciones. El monitoreo adecuado de la memoria no-heap es esencial, ya que no se gestiona mediante el recolector de basura, lo que implica que su uso incorrecto puede llevar a problemas de rendimiento y errores en la aplicación.
Comprendiendo la memoria no-heap
La memoria no-heap se utiliza para una variedad de propósitos en la JVM, incluyendo, pero no limitado a, la memoria para compiladores JIT, para almacenar clases y métodos cargados, y para estructuras internas de la JVM. Por lo tanto, es fundamental medir y entender el consumo de esta memoria para mejorar la eficiencia y la estabilidad de la aplicación.
2. jcmd
jcmd es una herramienta incluida con el JDK que permite enviar comandos de diagnóstico y resolución de problemas a un proceso Java en ejecución. La utilizamos para inspeccionar propiedades del sistema, desencadenar colecciones de basura, volcar información sobre el heap y los hilos, y gestionar la compilación JIT.
Uso de jcmd para monitorear memoria no-heap
Para monitorear la memoria no-heap utilizando
jcmd
, primero debemos habilitar Native Memory Tracking (NMT). Luego, podemos invocar jcmd
para obtener información del proceso de memoria:jcmd <pid> VM.native_memory
En la respuesta, podemos analizar todas las secciones de memoria no-heap que necesitamos:
- GC (reserved=359872KB, committed=70440KB)
(malloc=17792KB #582)
(mmap: reserved=342080KB, committed=52648KB)
- Compiler (reserved=168KB, committed=168KB)
(malloc=4KB #29)
(arena=165KB #5)
- Internal (reserved=221KB, committed=221KB)
(malloc=157KB #1202)
(mmap: reserved=64KB, committed=64KB)
En este output, podemos observar el consumo de memoria heap así como el consumo de todos los tipos de memoria no-heap. La propiedad committed indica el consumo en el momento de la llamada a
jcmd
.3. jconsole
jconsole es otra herramienta de monitoreo que cumple con la especificación de Java Management Extensions (JMX). Podemos usar
jconsole
para monitorear y gestionar aplicaciones Java en tiempo real en casos donde solo tenemos acceso al JDK.Uso de jconsole para monitorear memoria no-heap
jconsole
proporciona una interfaz gráfica que nos permite rastrear el uso de memoria, la actividad de los hilos, el consumo de CPU, y MBeans.Para ejecutar
jconsole
, ejecutamos el siguiente comando desde la carpeta bin
del JDK:<JDK_PATH>\bin\jconsole
En la primera pantalla, elegimos el proceso local o remoto al que queremos conectarnos. Luego, en la pestaña de Memoria, seleccionamos el gráfico de Uso de Memoria No-Heap, donde podremos ver visualmente el uso de esta memoria.
4. VisualVM
VisualVM es otra herramienta visual que proporciona capacidades de monitoreo de JVM. Usamos VisualVM para monitorear la carga de CPU, el uso de memoria, la actividad de hilos, y los volcado de heap. También es compatible con el análisis de volcaduras de hilos y el perfilado de la ejecución de métodos.
Monitorización de MetaSpace en VisualVM
En la configuración básica de VisualVM, podemos monitorear el tamaño de metaspace utilizando la pestaña de Monitor.
Monitorear Memoria No-Heap Usando el MBeans Plugin
Al agregar el complemento MBeans en VisualVM, veremos una nueva pestaña llamada MBeans. En esta pestaña, podemos ver el uso actual de memoria no-heap en general y para secciones de memoria específicas en particular.
Monitorizar Buffers Directos Usando el Buffer Pools Plugin
Además, podemos utilizar el complemento de Buffer Monitor de VisualVM. Tras la instalación, veremos la nueva pestaña Buffer Pools, donde podemos ver el uso actual de memoria de buffers directos y archivos mapeados en memoria.
5. Java Mission Control
Java Mission Control es otra herramienta visual que proporciona capacidades de monitoreo y diagnóstico de JVM. Utilizamos JMC para analizar el rendimiento de aplicaciones, monitorear el uso de memoria, inspeccionar la actividad de hilos y revisar el comportamiento de la recolección de basura.
Uso de Java Mission Control para monitorear la memoria no-heap
Al conectarnos a nuestra aplicación usando el MBean Server, en la pestaña de MBeans podemos encontrar la utilización total de memoria no-heap. Sin embargo, debemos tener en cuenta que este número no incluye el consumo de memoria del buffer directo.
Monitoreo de Native Memory Tracking Usando Registros JFR
Desde Java 20, podemos registrar continuamente los datos de Native Memory Tracking con Java Flight Recorder (JFR). Usando el siguiente comando, podemos preparar un archivo de grabación que incluya los eventos necesarios:
java -XX:NativeMemoryTracking=detail -XX:StartFlightRecording=name=Profiling,filename=nmt-recording.jfr,settings=profile -jar path/ourapp.jar
Luego, podemos abrir este archivo usando Java Mission Control. En la pestaña de Event Browser, podemos encontrar el evento Total Native Memory Usage, que muestra la cantidad total de memoria comprometida.
Al elegir el evento Native Memory Usage Per Type, obtendremos un desglose del consumo de todos los tipos de memoria no-heap.
6. JMX-DExporter
JMX-DExporter es una herramienta que expone métricas JMX en un formato compatible con Prometheus. Usamos JMX-DExporter para recolectar métricas de la JVM como el uso de memoria, la actividad de hilos, estadísticas de recolección de basura, y más.
Uso del Endpoint de Métricas en JMX-DExporter
Para comenzar a usar JMX-DExporter, primero debemos descargar el jar del agente. Luego, configuramos nuestro exportador utilizando jmx_exporter_config.yml:
startDelaySeconds: 0
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
- pattern: "java.lang:type=Memory"
name: "jvm_memory_usage_bytes"
labels:
area: "$2"
type: GAUGE
Ahora, podemos iniciar nuestra aplicación con el JMX-DExporter adjunto a ella:
java -javaagent:.path-to-agent-jar\jmx_prometheus_javaagent.jar=port:path-to-agent-jar\jmx_exporter_config.yml -jar .path-to-app\app.jar
Al llamar al endpoint
http://localhost:port/metrics
, veremos toda la información proporcionada por el Memory MBean, incluido el dato del uso de memoria no-heap.Integración con Prometheus
Prometheus es una herramienta de monitoreo y alerta de código abierto que utilizamos para recopilar y almacenar métricas como datos de series de tiempo. Podemos integrar fácilmente nuestro endpoint de métricas con Prometheus.
Modificamos el archivo prometheus.yml con los siguientes valores:
scrape_configs:
- job_name: "our_app"
static_configs:
- targets: ["localhost:port"]
Después de realizar los cambios en la configuración, reiniciamos la instancia de Prometheus y abrimos la consola. En el campo de entrada, podemos escribir cualquier métrica disponible, incluido el uso no-heap.
7. Conclusion
En este tutorial, revisamos un conjunto de herramientas que nos ayudan a monitorear el uso de memoria no-heap.
Para casos simples, cuando no necesitamos un informe detallado y tenemos acceso a la JDK, podemos considerar herramientas básicas como
jcmd
o jconsole
. Para casos más complejos, donde se necesitan conocimientos detallados sobre tipos específicos de memoria, podemos utilizar grabaciones de vuelos y JMC.Para integrar nuestro monitoreo en métricas de Prometheus, podemos usar el agente JMX-Exporter. La separación adicional de recursos consumidos por todas las herramientas de monitoreo debe ser considerada en cada caso específico.
Optimizar el uso de memoria no-heap puede ser crucial para mejorar el rendimiento de las aplicaciones. Asegúrate de elegir la herramienta adecuada según las necesidades de tu proyecto, ¡y feliz codificación!