¿Hay alguna manera de reducir el montón de Java cuando no está en uso?

Estoy trabajando en una aplicación Java en este momento y estoy trabajando para optimizar su uso de memoria. Estoy siguiendo las pautas para la recogida adecuada de basura, hasta donde yo sé. Sin embargo, parece que mi montón parece estar en su tamaño máximo, a pesar de que no es necesario.

Mi progtwig ejecuta una tarea de uso intensivo de recursos una vez por hora, cuando una persona no utiliza la computadora. Esta tarea utiliza una buena porción de memoria, pero luego la libera inmediatamente después de que la tarea finaliza. El generador de perfiles de NetBeans revela que el uso de memoria se ve así:

Uso de la memoria del programa Java

Realmente me gustaría devolver todo ese espacio dynamic al sistema operativo cuando no esté en uso. No hay ninguna razón para que lo acapare mientras que el progtwig ni siquiera hará nada por al menos otra hora.

es posible? Gracias.

Quizás -XX:MaxHeapFreeRatio jugar con -XX:MaxHeapFreeRatio : este es el porcentaje máximo (por defecto 70) del montón que está libre antes de que el GC lo reduzca. Tal vez establecerlo un poco más bajo (40 o 50?) Y luego usar System.gc() podría tomar algunas medidas para obtener el comportamiento deseado.

Sin embargo, no hay forma de forzar esto, puedes intentar y alentar a la JVM a que lo haga, pero no puedes simplemente arrancar la memoria cuando y como quieras. Y aunque lo anterior puede reducir el montón, esa memoria no se entregará directamente al sistema operativo (aunque en las implementaciones recientes de la JVM sí lo hace).

Versión corta: Sí, puedes.

Versión larga:

Cómo maneja Java / JVM la memoria

Para la mayoría de las aplicaciones, los valores predeterminados de JVM son correctos. Parece que la JVM espera que las aplicaciones se ejecuten solo durante un período de tiempo limitado. Por lo tanto, no parece liberar memoria por sí mismo.

Para ayudar a la JVM a decidir cómo y cuándo realizar la recolección de basura, se deben proporcionar los siguientes parámetros:

  • -Xms Especifica el tamaño mínimo de -Xms dynamic
  • –Xmx Especifica el tamaño de –Xmx dynamic máximo

Para aplicaciones de servidor, agregue: -server

Eso no es suficiente para mí. ¡Quiero más control!

En caso de que los parámetros mencionados anteriormente no sean suficientes, puede influir en el comportamiento de la JVM con respecto a la recolección de basura.

Primero, puede usar System.gc() para indicarle a la VM cuándo cree que la recolección de basura tendría sentido. Y segundo, puede especificar cuál de los recolectores de basura debe usar la JVM:

Diferentes tipos de recolectores de basura:

  • Serial GC

    Parámetro de línea de comando: -XX:+UseSerialGC

    Detiene su aplicación y realiza GC.

  • Paralelo GC

    Parámetro de línea de comando: -XX:+UseParallelGC -XX:ParallelGCThreads=value

    Ejecuta colecciones menores en paralelo con su aplicación. Reduce el tiempo necesario para colecciones importantes , pero usa otro hilo.

  • Parallel Compacting GC

    Parámetro de línea de comando: -XX:+UseParallelOldGC

    Ejecuta colecciones importantes en paralelo con su aplicación. Utiliza más recursos de CPU, reduce el uso de memoria.

  • CMS GC

    Parámetro de línea de comando: -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly

    Realiza colecciones más pequeñas, y más a menudo que Serial GC , lo que limita las interrupciones / paradas de la aplicación.

  • G1

    Parámetro de línea de comando: -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

    Experimental (al menos en Java 1.6): intenta asegurarse de que la aplicación nunca se detiene durante más de 1s.

    Ejemplo

Uso de memoria de una aplicación web de Play Framework sin optimizaciones: Play WebApp Framework sin optimizaciones Como puede ver, utiliza bastante espacio de montón, y el espacio utilizado se libera regularmente.

En este caso, las optimizaciones con parámetros solo no fueron efectivas. Hubo algunas tareas progtwigdas que usaron bastante memoria. En este caso, el mejor rendimiento se logró utilizando el CMS GC combinado con System.gc() después de las operaciones de memoria intensiva. Como resultado, el uso de la memoria de la aplicación web se redujo de 1,8 GB a alrededor de 400-500 MB.

Aquí puede ver otra captura de pantalla de VisualVM que muestra cómo la JVM libera la memoria y la devuelve al sistema operativo:

La JVM libera la memoria y la devuelve al sistema operativo Nota: Utilicé el botón “Realizar GC” de VisualVM para realizar el GC en lugar de System.gc() en mi código, ya que las tareas progtwigdas que consumen la memoria solo se inician en momentos específicos y es algo más difícil de capturar con VisualVM .

Otras lecturas

  • Artículo sobre la afinación de la JVM GC
  • Documentación de Oracle de los GC disponibles

Una posibilidad es hacer que su aplicación java de fondo inicie una instancia de jvm externa cada hora para ejecutar su tarea. De esta forma, solo su aplicación jvm original se ejecuta entre tareas.

La JVM no funciona de esa manera. No puedes devolverlo al sistema operativo.

Como señalaron varias personas desde que se escribió hace cuatro años, puede devolver la memoria al sistema operativo si le da la configuración correcta del GC a la JVM.

Si su aplicación está en reposo durante períodos de inactividad, es posible que el sistema operativo cambie esas páginas por usted, mitigando su presión sobre la memoria física.

http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/

El secreto mejor guardado de Java: -Xincgc Tiene un impacto en el rendimiento pero no siempre es tan grande. A veces sí lo hace, depende de lo que estés haciendo. ¡El recolector de basura incremental devuelve la memoria al sistema bastante bien!