management collector java garbage-collection monitoring memory-management

collector - ¿Cómo controlar el uso de la memoria de Java?



Tenemos una aplicación j2ee ejecutándose en Jboss y queremos monitorear su uso de memoria. Actualmente usamos el siguiente código

System.gc(); Runtime rt = Runtime.getRuntime(); long usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024; logger.information(this, "memory usage" + usedMB);

Este código funciona bien. Eso significa que muestra la curva de memoria que corresponde a la realidad. Cuando creamos un gran archivo xml a partir de un DB, una curva sube, una vez que la extracción finaliza, baja.

Un consultor nos dijo que llamar a gc () explícitamente es incorrecto, "dejar que jvm decida cuándo ejecutar gc". Básicamente, sus argumentos fueron los mismos que aquí se discuten . Pero todavía no entiendo:

  • ¿Cómo puedo tener mi curva de uso de memoria?
  • ¿Qué pasa con el explícito gc ()? No me importan los pequeños problemas de rendimiento que pueden ocurrir con el gc explícito () y que estimaría en un 1-3%. Lo que necesito es memoria y monitor de hilo que me ayuda en el análisis de nuestro sistema en el sitio del cliente.

Al agregar a la Lista de respuestas, JConsole (incluido en el directorio jdk / bin) también es una buena interfaz para probar.

Reference


Como se ha sugerido, pruebe VisualVM para obtener una vista básica.

También puede usar Eclipse MAT para hacer un análisis de memoria más detallado.

Está bien hacer un System.gc () siempre y cuando no dependas de él, para la corrección de tu programa.



Eche un vistazo a los argumentos de JVM: http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX: -PrintGC Imprimir mensajes en la recolección de basura. Manejable.

-XX: -PrintGCDetails Imprima más detalles en la recolección de basura. Manejable. (Introducido en 1.4.0)

-XX: -PrintGCTimeStamps Imprime las marcas de tiempo en la recolección de basura. Manejable (Introducido en 1.4.0)

-XX: -PrintTenuringDistribution Imprima información de edad de tenencia.

Si bien no vas a alterar la JVM con llamadas explícitas a System.gc() es posible que no tengan el efecto que estás esperando. Para entender realmente qué está pasando con la memoria en una JVM con leer cualquier cosa y todo lo que escribe Brian Goetz .


El problema con system.gc es que la JVM ya asigna automáticamente tiempo al recolector de basura según el uso de la memoria.

Sin embargo, si usted está, por ejemplo, trabajando en una condición limitada de memoria, como un dispositivo móvil, System.gc le permite asignar manualmente más tiempo hacia esta recolección de basura, pero a costa de tiempo de CPU (pero, como dijo , no le preocupan los problemas de rendimiento de gc).

La mejor práctica sería probablemente usarla solo en los casos en que esté haciendo grandes cantidades de desasignación (como enjuagar un conjunto grande).

Todos considerados, ya que simplemente está preocupado por el uso de la memoria, no dude en llamar a gc o, mejor aún, vea si hace una gran diferencia de memoria en su caso, y luego decida.


Hay herramientas que le permiten monitorear el uso de la memoria de la VM. La VM puede exponer estadísticas de memoria usando JMX . También puede imprimir estadísticas de GC para ver cómo se desempeña la memoria a lo largo del tiempo.

Invocar System.gc () puede dañar el rendimiento del GC porque los objetos se moverán prematuramente de los nuevos a las generaciones anteriores, y las referencias débiles se borrarán prematuramente. Esto puede dar como resultado una disminución de la eficiencia de la memoria, tiempos de GC más largos y una disminución de los hits de caché (para cachés que utilizan refs débiles). Estoy de acuerdo con su consultor: System.gc () es malo. Iría tan lejos como para desactivarlo usando el interruptor de línea de comando.


La ejecución explícita de System.gc () en un sistema de producción es una idea terrible. Si la memoria llega a cualquier tamaño, todo el sistema puede congelarse mientras se está ejecutando un GC completo. En un servidor de varios gigabytes, esto puede ser muy notable, dependiendo de cómo esté configurado el jvm, y de cuánto espacio libre tenga, etc. - He visto pausas de más de 30 segundos.

Otro problema es que al llamar explícitamente a GC, en realidad no está monitoreando cómo la JVM está ejecutando el GC, en realidad lo está alterando, dependiendo de cómo haya configurado la JVM, se va a recolectar basura cuando sea apropiado, y generalmente incrementalmente (No solo ejecuta un GC completo cuando se queda sin memoria). Lo que va a imprimir no se parecerá en nada a lo que JVM hará por sí solo; por un lado, probablemente verá menos GC automáticos / incrementales ya que borrará la memoria manualmente.

Como señala la publicación de Nick Holt, las opciones para imprimir actividad de GC ya existen como indicadores de JVM.

Puede tener un hilo que se imprime gratis y disponible a intervalos razonables, esto le mostrará el uso real de la memoria.


Puedes echar un vistazo a stagemonitor . Es un monitor de rendimiento de aplicación java (web) de código abierto. Captura métricas de tiempo de respuesta, métricas de JVM, detalles de solicitud (incluida una pila de llamadas capturadas por el generador de perfiles de solicitud) y más. La sobrecarga es muy baja.

Opcionalmente, puede usar el gran grafito de base de datos de timeseries con este para almacenar un largo historial de puntos de datos que puede ver con paneles de lujo.

Ejemplo:

Eche un vistazo al stagemonitor del stagemonitor para ver capturas de pantalla, descripciones de funciones y documentación.

Nota: soy el desarrollador de stagemonitor



Si realmente quieres ver lo que está sucediendo en la memoria de la VM, debes usar una buena herramienta como VisualVM . Este software es gratuito y es una excelente manera de ver lo que está sucediendo.

Nada está realmente "mal" con las llamadas explícitas de gc (). Sin embargo, recuerde que cuando llama a gc () está "sugiriendo" que se ejecute el recolector de elementos no utilizados. No hay garantía de que se ejecutará en el momento exacto en que ejecuta ese comando.



Si utiliza el historial de carreras de GC proporcionado por JMX puede usar los mismos números de antes / después, simplemente no tiene que forzar un GC.

Solo debe tener en cuenta que esas ejecuciones GC (generalmente una para la generación anterior y otra para la nueva generación) no están en intervalos regulares, por lo que necesita extraer el tiempo de inicio también para trazar (o trazar contra un número de secuencia, para la mayoría fines prácticos que serían suficientes para trazar).

Por ejemplo, en Oracle HotSpot VM con ParNewGC, hay un MBean JMX llamado java.lang:type=GarbageCollector,name=PS Scavenge , tiene un atributo LastGCInfo, devuelve un CompositeData de la última ejecución de YG scavenger. Se registra con duration , memoryUsageBefore memoryUsageAfter absoluta y uso de memoryUsageBefore y uso de memoryUsageAfter .

Solo usa un temporizador para leer ese atributo. Cada vez que se muestra un nuevo horario de inicio, usted sabe que describe un nuevo evento del GC, extrae la información de la memoria y sigue sondeando para la próxima actualización. (No estoy seguro de si se puede usar AttributeChangeNotification alguna manera).

Consejo: en su temporizador puede medir la distancia hasta la última ejecución del GC, y si eso es demasiado largo para la consecución de su trazado, puede invocar a System.gc () condicionalmente. Pero no haría eso en una instancia de OLTP.


Yo diría que el consultor tiene razón en la teoría, y usted tiene razón en la práctica. Como dice el refrán :

En teoría, teoría y práctica son lo mismo. En la práctica, no lo son.

La especificación de Java dice que System.gc sugiere llamar a la recolección de basura. En la práctica, solo genera un hilo y se ejecuta inmediatamente en Sun JVM.

Aunque en teoría podría estar estropeando una implementación JVM finamente ajustada de la recolección de basura, a menos que esté escribiendo un código genérico destinado a ser implementado en cualquier JVM, no se preocupe. Si funciona para ti, hazlo.