java - useconcmarksweepgc - ¿Alentar la JVM a GC en lugar de crecer el montón?
jvm parameters (4)
(Tenga en cuenta que cuando digo "JVM", realmente me refiero a "Hotspot", y estoy ejecutando la última actualización de Java 1.6).
Situación de ejemplo:
Mi JVM se ejecuta con -Xmx establecido en 1 gb. Actualmente, el montón tiene 500 mb asignados, de los cuales se utilizan 450 mb. El programa necesita cargar otros 200 mb en el montón. Actualmente, hay 300 mb de basura "coleccionable" en el montón (asumiremos que todo está en la generación más antigua).
En condiciones normales de funcionamiento, la JVM hará crecer el montón a 700 mb o menos, y la recolección de basura cuando llegue a ese punto.
Lo que me gustaría en esa situación es que la JVM gc primero, luego asigne las cosas nuevas, de modo que terminemos con el tamaño del montón de 500 MB y el montón usado a 350 MB.
¿Hay un combo de parámetros JVM que hace eso?
Como de costumbre, podría invocar el método System.gc()
antes de asignar los 200 MB adicionales de objetos, pero esto solo será una sugerencia para la JVM que puede o no puede seguir y en ningún caso no sabrá cuándo tendrá lugar. Como se indica en la documentación, es una solicitud de mejor esfuerzo.
Por cierto, tenga en cuenta que la recolección de basura es una operación pesada, por lo que si no hay una necesidad específica de hacerlo, no intente forzarla.
Solo para saber: si configura -Xmx1G
, le está diciendo a la JVM que 1GB es el espacio máximo para el montón, y dado que está especificando eso, no veo por qué debería intentar mantenerlo bajo si sabe eso 1GB aún estará bien (estamos en el contexto de lenguajes administrados por memoria). Si no desea que el montón aumente, solo disminuya el valor máximo para que se vea forzado a hacer GC antes de asignar nuevos objetos, de lo contrario, ¿por qué le está diciendo que use 1GB?
Hay cuatro (en realidad, cinco) recolectores de basura diferentes en HotSpot, y sus opciones son diferentes para cada uno.
- El colector en serie tiene
-XX:MinHeapFreeRatio
y-XX:MaxHeapFreeRatio
, que le permiten controlar el comportamiento de forma más o menos directa. Sin embargo, no tengo mucha experiencia con el coleccionista en serie. - El recopilador paralelo (
-XX:+UseParallelOldGC
) tiene-XX:MaxGCPauseMillis=<millis>
y-XX:GCTimeRatio=<N>
. La configuración de un tiempo de pausa máximo inferior generalmente hace que el recopilador reduzca el tamaño del montón. Sin embargo, si el tiempo de pausa ya es pequeño, el montón no será más pequeño. OTOH, si el tiempo máximo de pausa es demasiado bajo, la aplicación puede pasar todo su tiempo recolectando. Establecer una relación de tiempo gc más baja generalmente también hace que el montón sea más pequeño. Le está diciendo a gc que está dispuesto a dedicar más tiempo de CPU a la recopilación a cambio de un montón más pequeño. Sin embargo, esto es solo una sugerencia y puede no tener ningún efecto. En mi opinión, el colector paralelo es casi ininteligible con el fin de minimizar el tamaño del montón. Este recopilador funciona mejor (se sintoniza) si lo dejas correr por un tiempo y el comportamiento de la aplicación permanece constante. - El recopilador de CMS (
-XX:+UseConcMarkSweepGC
) generalmente requiere un montón más grande para lograr su objetivo principal de tiempo de pausa bajo, por lo que no lo discutiré. - El nuevo coleccionista G1 (
-XX:+UseG1GC
) no es tan cerebral como los coleccionistas más antiguos. Encuentro que elige un tamaño de pila más pequeño por sí solo. Tiene muchas opciones de ajuste, aunque solo he empezado a estudiarlas.-XX:InitiatingHeapOccupancyPercent
,-XX:G1HeapWastePercent
,-XX:G1ReservePercent
y-XX:G1MaxNewSizePercent
pueden ser de su interés.
Eche un vistazo a la documentación oficial para los recolectores de basura, así como a esta lista de banderas .
Recomiendo echar un vistazo aquí:
Puede intentar especificar -XX:MinHeapFreeRatio
y -XX:MaxHeapFreeRatio
para controlar la expansión del montón y la reducción:
-
-XX:MinHeapFreeRatio
: cuando el porcentaje de espacio libre en una generación cae por debajo de este valor, la generación se expandirá para cumplir con este porcentaje. El valor predeterminado es 40. -
-XX:MaxHeapFreeRatio
: cuando el porcentaje de espacio libre en una generación excede este valor, la generación se reducirá para alcanzar este valor. El valor predeterminado es 70.
También es posible que desee experimentar con GC concurrente especificando -XX:+UseConcMarkSweepGC
. Dependiendo de su aplicación, podría mantener el tamaño del montón más bajo al costo de ciclos de CPU adicionales.
De lo contrario, la JVM utilizará la memoria que especifique como disponible cuando sea óptimo hacerlo. Podría especificar una cantidad menor como -Xmx768m
para mantenerla contenida y podría funcionar bien, aunque aumentaría el riesgo de quedarse sin memoria en un escenario de carga pesada. Realmente, la única forma de usar menos memoria en general es escribir código que use menos memoria :)