2011-03-18 9 views
15

(Tenga en cuenta que cuando digo "JVM", me refiero a "hotspot", y estoy usando la última actualización de Java 1.6.)¿Alienta la JVM a GC en lugar de hacer crecer el montón?

situación Ejemplo:

Mi JVM está funcionando con el sistema -Xmx a 1 gb. Actualmente, el montón tiene 500mb asignados, de los cuales se utilizan 450mb. El programa necesita cargar otros 200 mb en el montón. Actualmente, hay 300 MB de basura "coleccionable" en el montón (asumiremos que está en la generación más antigua).

En condiciones normales de funcionamiento, la JVM aumentará el montón a 700 MB aproximadamente, y se recogerá la basura cuando llega el momento.

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 de pila permaneciendo en 500mb, y el montón usado en 350mb.

¿Hay un combo de parámetros JVM que lo haga?

Respuesta

2

Por lo general, puede invocar el método System.gc() antes de asignar los 200MB adicionales de objetos, pero esto solo indicará a la JVM que puede o no seguir y en cualquier caso no sabrá cuándo se produce. 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, simplemente 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 ya que está especificando eso, no veo por qué debería tratar de mantenerlo bajo si sabe que 1GB seguirá estando bien (estamos en el contexto de los lenguajes administrados por memoria). Si no desea que el montón aumente mucho, simplemente disminuya el valor máximo para que se vea forzado a hacer GC antes de asignar nuevos objetos. De lo contrario, ¿por qué le dice que use 1 GB?

+1

El concepto de que no hay necesidad de liberar la memoria no utilizada es, en mi opinión, el principal problema con los lenguajes de programación "modernos" de la actualidad. Comparto las preocupaciones de Electrons_Ahoy. Las computadoras ya no son más rápidas como solían, desafortunadamente. ¡Tenemos que escribir un mejor software! – Seba

+0

Esa es la compensación si quieres olvidarte de la asignación de memoria, nada extraño ni nada que te prohíba usar C o C++ y administrar lo que quieras a mano. Pero si elige un entorno que se encargue de comportarse de la mejor manera por sí solo, entonces no debería intentar forzar su comportamiento. Su argumentación es en gran parte inútil ya que estamos en el contexto de Java, y nadie lo obliga a usarlo :) Es como discutir contra alguien con un gran vehículo contaminante, simplemente tome su bicicleta y olvídese de la contaminación. – Jack

+0

Esto podría ser útil , en eso, un gc completo será más barato cuando el montón utilizado sea más pequeño. Si pudiera elegir entre "fullGC now-> recover 500M-> add 500M of new objects" y "add 500M-> trigger an automatic GC-> recover 500M", el primero sería más económico. Además, aunque los documentos establecen explícitamente que System.gc() se tomará como "una sugerencia", funciona como si se hubiera escrito como obligatorio en mi juego limitado. No es que sea necesariamente una buena idea: con un montón de 1G, un fullgc causará un bloqueo notable, al menos unos pocos segundos totalmente bloqueados. –

10

usted podría intentar especificar -XX:MinHeapFreeRatio y -XX:MaxHeapFreeRatio para controlar la expansión y la contracción del montón:

  • -XX:MinHeapFreeRatio - cuando el porcentaje de espacio libre en una generación cae por debajo de este valor la generación se ampliará 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 cumplir con este valor. El valor predeterminado es 70.

Es posible que también desee experimentar con el GC concurrente especificando -XX:+UseConcMarkSweepGC. Dependiendo de su aplicación, podría mantener el tamaño del montón más bajo a costa de ciclos de CPU adicionales.

De lo contrario, la JVM va a utilizar la memoria que especifique como disponible cuando sea óptimo para hacerlo. Puede especificar una cantidad menor como -Xmx768m para mantenerla contenida y puede funcionar bien, aunque aumentaría el riesgo de quedarse sin memoria en un escenario de carga pesada.Realmente la única manera de usar menos memoria en general es escribir código que utiliza menos memoria :)

+0

-1 Estas opciones se aplican solo al recolector de basura ** serial ** (es decir, el que ya nadie usa). Además, 'CMS' es generalmente inferior a' G1', aunque tal vez su respuesta sea anterior a él. –

+0

@AleksandrDubinsky Si bien 'G1' es un muy buen recopilador, en Java 7 es totalmente inadecuado para cualquier sistema sensible a la latencia que hace mucha carga y descarga de clases, ya que no recopila permgen. Java 8 no tiene ese problema – Leliel

+0

@Leliel No creo que ningún recopilador recopile permgen en Java 7. De ahí el nombre "generación permanente". –

8

Hay cuatro (en realidad, cinco) diferentes recolectores de basura en HotSpot, y sus opciones son diferentes para cada uno.

  • El colector de serie tiene -XX:MinHeapFreeRatio y -XX:MaxHeapFreeRatio, que le permiten controlar más o menos directamente el comportamiento. Sin embargo, no tengo mucha experiencia con el colector serial.
  • El colector paralelo (-XX:+UseParallelOldGC) tiene -XX:MaxGCPauseMillis=<millis> y -XX:GCTimeRatio=<N>. Establecer un tiempo de pausa máximo inferior generalmente hace que el recolector reduzca el montón. Sin embargo, si el tiempo de pausa ya es pequeño, el montón no se reducirá. OTOH, si el tiempo máximo de pausa es demasiado bajo, la aplicación puede pasar todo el tiempo recogiendo. Establecer una relación de tiempo gc menor también generalmente hace que el montón sea más pequeño. Le está diciendo al 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 pista y puede no tener ningún efecto. En mi opinión, el colector paralelo es casi indestructible con el fin de minimizar el tamaño del montón. Este recopilador funciona mejor (se sintoniza) si lo dejas funcionar por un tiempo y el comportamiento de la aplicación se mantiene constante.
  • El recopilador CMS (-XX:+UseConcMarkSweepGC) generalmente requiere un montón más grande para lograr su objetivo principal de tiempo de pausa baja, por lo que no voy a discutirlo.
  • El nuevo colector G1 (-XX:+UseG1GC) no tiene la muerte cerebral como los coleccionistas más antiguos. Encuentro que elige un tamaño de montón más pequeño por sí mismo. Tiene muchas opciones de ajuste, aunque recién comencé a estudiarlas. -XX:InitiatingHeapOccupancyPercent, -XX:G1HeapWastePercent, -XX:G1ReservePercent y -XX:G1MaxNewSizePercent pueden ser de su interés.

Eche un vistazo a official documentation para los recolectores de basura, así como this list of flags.

Cuestiones relacionadas