¿Cómo realiza JAVA la recolección de basura?
Antes de que Java comenzara la recolección de basura, escuché al maestro decir que parecía que la memoria estaba llena, por lo que hizo una recolección de basura general mientras reciclaba. basura, llamaría al método de finalización. Puede anular el método de finalización al crear una clase y dejar que la clase ejecute algún código durante la recolección de basura, como liberar recursos.
1. Descripción general del GC de JVM
JVM utiliza el mecanismo de recolección de basura GC para liberar la memoria ocupada por objetos que ya no se utilizan. Sin embargo, todas las JVM de uso común tienen recolectores de basura, y la mayoría de los recolectores de basura usan algoritmos similares para administrar la memoria y realizar operaciones de recolección.
El algoritmo de recolección de basura y el proceso de ejecución solo se pueden optimizar eficazmente para el rendimiento si se comprenden completamente. Algunas recolecciones de basura están diseñadas para aplicaciones específicas. Por ejemplo, las aplicaciones en tiempo real tratan principalmente de evitar interrupciones en la recolección de basura, mientras que la mayoría de las aplicaciones OLTP se centran en la eficiencia general. Una vez que comprenda la carga de trabajo de su aplicación y los algoritmos de recolección de basura admitidos por su JVM, podrá optimizar la configuración de su recolector de basura.
El propósito de la recolección de basura es eliminar objetos que ya no se utilizan. El GC determina si se debe recopilar un objeto determinando si un objeto activo hace referencia a él. Dos métodos comúnmente utilizados son el recuento de referencias y el recorrido de referencias de objetos.
1.1. Recuento de referencias
El recuento de referencias almacena el número de todas las referencias a un objeto específico, lo que significa que cuando la aplicación crea una referencia y la referencia sale del alcance, el jvm debe hacerlo. Incrementar o disminuir apropiadamente el recuento de referencia. Cuando el recuento de referencias de un objeto llega a 0, se puede recolectar basura.
1.2. Recorrido de referencias de objetos
Las primeras JVM usaban el recuento de referencias y ahora la mayoría de las JVM usan el recorrido de referencias de objetos. El recorrido de referencia de objetos comienza a partir de un conjunto de objetos y determina de forma recursiva los objetos alcanzables a lo largo de cada enlace en todo el gráfico de objetos. Si no se puede acceder a un objeto desde uno (o al menos uno) de sus objetos raíz, se recolectará como basura. Durante la fase de recorrido del objeto, el gc debe recordar qué objetos son accesibles para poder eliminar los objetos inalcanzables, que son los llamados objetos marcados.
A continuación, el gc elimina los objetos inaccesibles. Al eliminar, algunos gcs simplemente escanean la pila, eliminan los objetos no marcados y luego liberan la memoria para generar nuevos objetos, lo que se denomina barrido. El problema con este enfoque es que la memoria se divide en muchos segmentos pequeños que no son lo suficientemente grandes para acomodar nuevos objetos, pero sí son grandes cuando se combinan. Por lo tanto, muchos gcs pueden reorganizar objetos en la memoria y comprimirlos para crear espacio libre.
Para ello, el gc necesita detener otras actividades. Este enfoque significa que todo el trabajo relacionado con la aplicación se detiene y solo se ejecuta gc. Por lo tanto, muchas solicitudes mixtas se suman o restan durante el proceso de respuesta. Además, se agregan o ejecutan gcs más complejos al mismo tiempo para minimizar o eliminar las interrupciones de la aplicación. Algunos gcs utilizan un solo subproceso para realizar el trabajo, mientras que otros utilizan varios subprocesos para mejorar la eficiencia.
2 Mecanismo de recolección de basura
2.1. Recolector de marcas y borrados
Este recolector primero atraviesa el gráfico de objetos y marca los objetos accesibles, y luego escanea la pila de objetos sin etiquetar. y liberar su memoria. Este recopilador normalmente funciona usando un solo hilo y detiene otras operaciones.
2.2. Recolector de marcas-barrido-compacto
A veces también llamado recolector de marcas-barrido-compacto, su fase de marcado es la misma que la del recolector de marcas-barrido. En la segunda fase, el objeto marcador se copia en una nueva área de la pila para compactar la pila. El recolector también detiene otras operaciones.
2.3. Coleccionista de copias
Este recopilador divide la pila en dos dominios, a menudo llamados medios espacios. gc comprime la pila copiando objetos accesibles en la otra mitad del espacio en tiempo de ejecución. Este método es adecuado para objetos con un ciclo de vida corto; copiar continuamente objetos con un ciclo de vida largo reducirá la eficiencia.
2.4. Recolector incremental
El recolector incremental divide la pila en múltiples campos y solo recolecta basura de un campo a la vez. Esto puede provocar interrupciones menores en la aplicación.
2.5. Recolector de generación dividida
Este tipo de recopilador divide la pila en dos o más dominios para acomodar objetos con diferentes ciclos de vida. Después de un período de tiempo, a los objetos que continúan existiendo se les da un ciclo de vida y se trasladan a un dominio con un ciclo de vida más largo. Los recopiladores generacionales utilizan diferentes algoritmos para diferentes dominios para optimizar el rendimiento.
2.6. Recopilador concurrente
El recopilador concurrente se ejecuta al mismo tiempo que la aplicación. Estos recopiladores a menudo necesitan detener otras operaciones en algún momento (como durante la compactación) para completar una tarea específica, pero dado que otras aplicaciones pueden realizar otras operaciones en segundo plano, el tiempo real para interrumpir otros procesos se reduce considerablemente.
2.7. Recolector paralelo
El recopilador paralelo utiliza algún algoritmo tradicional y utiliza múltiples subprocesos para realizar el trabajo en paralelo. El uso de tecnología de subprocesos múltiples en máquinas con múltiples CPU puede mejorar significativamente la escalabilidad de las aplicaciones Java.
3. Sun HotSpot
1.4.1 Ajuste del tamaño del montón JVM
Sun HotSpot 1.4.1 utiliza un recopilador generacional, que divide el montón en tres dominios primarios. : dominio nuevo, dominio antiguo y dominio permanente. Una vez que un objeto ha pasado por una cierta cantidad de ciclos de recolección de basura, adquiere una vida útil y ingresa al dominio anterior. En el dominio persistente, la JVM almacena objetos de clase y método. A efectos de configuración, el dominio persistente es un dominio independiente y no se considera parte del montón.
A continuación se explica cómo controlar el tamaño de estos campos. Puede utilizar -Xms y -Xmx para controlar el tamaño original o máximo de todo el montón.
El siguiente comando establece el tamaño inicial en 128M:
java -Xms128m
-Xmx256m Para controlar el tamaño del nuevo dominio, utilice -XX: Configuración de NewRatio La proporción del montón ocupada por el nuevo dominio.
El siguiente comando establece todo el montón en 128 m y la proporción del nuevo dominio en 3, lo que significa que la proporción del nuevo dominio con respecto al antiguo es 1:3 y el nuevo dominio ocupa 1/4 del montón o 32M:
java -Xms128m -Xmx128m
- XX:NewRatio =3 Puede usar -XX:NewSize y -XX:MaxNewsize para establecer el valor inicial y máximo valor del nuevo dominio.
El siguiente comando establece el tamaño inicial y máximo del nuevo dominio en 64 m:
java -Xms256m -Xmx256m -Xmn64m
El tamaño predeterminado del dominio permanente El dominio es de 4m. Cuando ejecute su programa, la jvm cambiará el tamaño del dominio persistente para adaptarlo a sus necesidades. Cada vez que haga esto, la jvm realizará una recolección de basura completa del montón.
Utilice el indicador -XX:MaxPerSize para aumentar el tamaño del dominio de persistencia. A medida que una aplicación WebLogic Server carga más clases, a menudo es necesario aumentar el tamaño máximo del dominio de persistencia. Cuando la JVM carga una clase, la cantidad de objetos en el dominio de persistencia aumenta drásticamente, lo que hace que la JVM ajuste continuamente el tamaño del dominio de persistencia. Para evitar el ajuste, utilice el indicador -XX:PerSize para establecer un valor inicial.
A continuación, el valor inicial del dominio permanente se establece en 32 m y el valor máximo se establece en 64 m.
java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m
De forma predeterminada, HotSpot utiliza un nuevo dominio en el recopilador de replicación. El dominio generalmente se divide en tres partes. La primera parte es Eden, que se utiliza para generar nuevos objetos. Cuando Eden está lleno, el recolector detiene la aplicación y copia todos los objetos accesibles en el espacio de rescate actual. Una vez que el espacio esclavo actual está lleno, el recopilador copia los objetos accesibles en el espacio esclavo actual. Los objetos que permanezcan activos se seguirán copiando en el espacio de rescate hasta que lleguen a su fecha de caducidad y se transfieran al dominio antiguo. Utilice -XX:SurvivorRatio para controlar el tamaño del nuevo subespacio de dominio.
Al igual que NewRation, SurvivorRation especifica la proporción entre un dominio de rescate específico y el espacio Eden. Por ejemplo, el siguiente comando establece el nuevo dominio en 64 m, de los cuales Eden representa 32 m y cada dominio de rescate representa 16 m:
java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2
Como se mencionó anteriormente, de forma predeterminada, HotSpot utiliza el recolector de copias para dominios nuevos y el recolector mark-clean-compact para dominios antiguos. Usar un recopilador de copias para nuevos dominios tiene sentido porque la mayoría de los objetos generados por una aplicación tienen una vida corta. Idealmente, todos los objetos de transición se recolectarán a medida que salgan del espacio del Edén. Si esto pudiera hacerse, y los objetos sacados del espacio del Edén tuvieran una vida más larga, entonces, en teoría, podrían trasladarse inmediatamente al antiguo espacio, evitando la duplicación en el espacio de rescate. Sin embargo, las aplicaciones no pueden adaptarse a este estado ideal porque tienen una pequeña proporción de objetos de mediano y largo plazo. Lo mejor que puede hacer es conservar estos objetos a mediano y largo plazo y colocarlos en un nuevo dominio, ya que siempre es más barato copiar un pequeño conjunto de objetos que compactar el dominio anterior. Para controlar la copia de objetos en un nuevo dominio, puede usar -XX:TargetSurvivorRatio (este valor establece la proporción del espacio de rescate utilizado) para controlar la proporción del espacio de rescate. Si los bits de espacio de recuperación son 1 millón, un valor de 50 significa 500.000 espacios libres). El valor es un porcentaje y el valor predeterminado es 50. Cuando las pilas más grandes utilizan una tasa de supervivencia más baja, este valor debe aumentarse de 80 a 90 para utilizar mejor el espacio residual. Puede utilizar -XX:maxtenuring umbral para controlar el límite superior.
Para permitir que se complete toda la replicación y que los objetos se extiendan desde Eden al dominio anterior, establezca el umbral MaxTenuring en 0. Una vez establecido en 0, el espacio de rescate en realidad ya no se usa, por lo que SurvivorRatio debe establecerse en el valor máximo para maximizar el uso del espacio Eden, configurado de la siguiente manera:
java ...-XX: MaxTenuringThreshold= 0 -XX:SurvivorRatio=50000 ...
4.Uso de BEA JRockit JVM
Bea WebLogic 8.1 utiliza una nueva JVM para plataformas Intel. Puede ver una carpeta similar a jrockit81sp1_141_03 en el directorio donde está instalado Bea. Este es el directorio donde se encuentra la nueva JVM de Bea. A diferencia de HotSpot, que compila el código de bytes de Java en código nativo, está precompilado en clases. jRockit también proporciona funciones más detalladas para observar el estado de ejecución de la JVM, principalmente una consola GUI independiente (solo se puede usar para usar Jrockit para monitorear algunos parámetros de CPU y memoria usando la consola que viene con jrockit81sp1_141_03) o WebLogic.
Bea JRockit JVM soporta cuatro tipos de recolectores de basura:
4.1.1 Generación separada de recolectores de copia
Su estrategia de trabajo está separada de la predeterminada Generación. un coleccionista es similar. El objeto se asigna a un nuevo dominio, el vivero en el documento JRockit. Este recopilador es más adecuado para operaciones de montón pequeñas en máquinas con una sola CPU.
4.1.2. Recopilador concurrente de espacio único
Este recopilador utiliza el montón completo y trabaja con subprocesos en segundo plano. Aunque este tipo de recopilador elimina las interrupciones, el recopilador tarda más en encontrar objetos muertos y se ejecuta con frecuencia mientras procesa la aplicación. Si el procesador no puede manejar la basura generada por el programa, interrumpe la aplicación y cierra el recolector.
Recopilador concurrente independiente Este recopilador utiliza un recopilador de replicación exclusivo en el dominio alojado y un recopilador concurrente en el dominio anterior. Debido a que interrumpe con más frecuencia que un recopilador concurrente *** de espacio único, requiere menos memoria y las aplicaciones se ejecutan de manera más eficiente.
Tenga en cuenta que alojar un dominio que es demasiado pequeño puede dar lugar a que una gran cantidad de objetos temporales se extiendan al dominio antiguo. Esto puede provocar que el recopilador se sobrecargue o incluso que se utilicen soluciones alternativas de exclusión para completar la colección.
4.1.3. Recopilador paralelo
Este recopilador también detendrá el trabajo de otros procesos, pero utilizará múltiples subprocesos para acelerar el proceso de recopilación. Aunque suele provocar interrupciones más largas que otros recopiladores, en general aprovecha mejor la memoria y el programa es más eficiente.
De forma predeterminada, JRockit utiliza un recopilador concurrente ramificado. Para cambiar el recopilador, utilice -Xgc:, que corresponde a los cuatro recopiladores: gencopy, singlecon, gencon y paralelo. Utilice -Xms y -Xmx para establecer el tamaño del montón inicial y máximo. Para configurar el campo de intercalación, use -
Nota: Si está utilizando JRockit JVM, también puede usar la consola WLS (ubicada en C:\bea\jrockit81sp1_141_03\bin) para monitorear la CPU, la memoria y otros datos. Para hacer esto, se debe iniciar la JVM. Para habilitar la supervisión, debe agregar el parámetro -Xmanagement en startWeblogic.cmd al iniciar el servicio.
5. Cómo obtener información de la JVM para realizar ajustes
El modificador -verbose.gc mostrará las operaciones en curso del gc. Al activarlo, se mostrará cuándo se produjeron las recopilaciones más ocupadas e inactivas, el tamaño de la memoria antes y después de las recopilaciones, cuánto tiempo tardaron las recopilaciones y más. Active el modificador -xx:+printgcdetails para ver los cambios de gc en detalle. Activar el modificador -xx:+PrintGCTimeStamps le indicará cuánto tiempo duraron estas recolecciones de basura, en segundos después de que se inició la jvm. Finalmente, active el modificador -xx:+PrintHeapAtGC para ver el montón con más detalle. Para obtener información sobre nuevos dominios, puede utilizar el modificador -XX:=PrintTenuringDistribution para obtener información sobre los permisos de objetos que obtienen tenencia.
6. Ajuste de JVM del sistema Pdm
6.1. Servidor: el requisito previo es que la memoria sea 1G y una sola CPU
Puede utilizar los siguientes parámetros para ajustar. : -server Habilita el modo servidor (recomendado para máquinas servidor si tiene varias CPU)
-Xms, -Xmx generalmente están configurados en el mismo tamaño. 800m
-Xmn establece NewSize y MaxNewSize iguales. 320m
-XX:PerSize 64m
-XX:NewSize 320m Este valor se puede ajustar a un tamaño mayor. NewSize 320m Este valor se puede ajustar para reducir el número de GC completos aumentando el área del nuevo objeto
-XX:MaxNewSize 320m
-XX:NewRato NewSize se puede configurar o dejar sin cambios .
-XX:SurvivorRatio
-XX:userParNewGC se puede usar para configurar una colección paralela
-XX:ParallelGCThreads se puede usar para aumentar el paralelismo
-XX: ParallelGCThreads se puede usar para aumentar el paralelismo
-XXUserParNewGC se puede usar para aumentar el paralelismo
-XXUseParallelGC se puede configurar para usar el recolector de limpieza paralelo
-XX: UseAdaptiveSizePolicy se utiliza mejor junto con la estrategia anterior y se puede utilizar para optimizar automáticamente nuevos tamaños de dominio y ahorrar proporciones de espacio
Cliente: ajuste la JVM del cliente configurando parámetros en. el archivo JNLP
Parámetros en JNLP: tamaño de montón inicial y tamaño de montón máximo
Esto se puede lograr agregando los parámetros anteriores al generar el archivo JNLP en el RequestManager del marco. . Se recomienda configurar estos dos parámetros al 60% de la memoria disponible del cliente (para probar). Para generar dinámicamente un JNLP utilizando los dos valores de parámetros anteriores (los valores de los parámetros pueden ser diferentes para diferentes clientes), la información sobre el sistema del cliente debe obtenerse de manera confiable e incrustarse como un parámetro de la solicitud de conexión en la página de inicio. índice.jsp.
Después de configurar los parámetros anteriores, puede usar Visualgc para observar el estado de algunos parámetros de recolección de basura y luego realizar ajustes para mejorar el rendimiento. El estándar general es reducir la cantidad de fullgc; el soporte de hardware es mejor utilizar la recolección de basura paralela (requiere varias CPU).