Entrada de JVM a la competencia

1. El concepto de JVM

1.1 ¿Qué es JVM?

  • Máquina virtual Java: máquina virtual Java, utilizada para garantizar que el lenguaje Java sea multiplataforma.

  • La máquina virtual Java puede considerarse como una computadora abstracta: como una computadora real, tiene su propio conjunto de instrucciones y varias áreas de memoria de tiempo de ejecución.

  • La máquina virtual Java no tiene necesaria conexión con el lenguaje Java, sólo está asociada a un formato de archivo binario específico (formato de archivo de clase)

  • La máquina virtual Java es un traductor de códigos de bytes, que traduce archivos de códigos de bytes en códigos de máquina correspondientes a cada sistema para garantizar que los archivos de códigos de bytes se puedan ejecutar correctamente en cada sistema.

  • El llamado java puede lograr multiplataforma, porque está determinado por la ejecución de diferentes máquinas virtuales en diferentes plataformas, por lo que la ejecución de archivos java no se ejecuta directamente en el sistema operativo.

  • En cambio, se ejecuta a través de la máquina virtual jvm. En esta imagen podemos ver que la JVM no trata directamente con el hardware, sino que interactúa con el sistema operativo para ejecutar programas java.

beneficio:

  • Escribe una vez, corre a cualquier lugar
  • Gestión automática de memoria, función de recolección de basura.
  • Verificación de subíndice de matriz fuera de límites
  • Polimorfismo

1.2 Composición de JVM

Insertar descripción de la imagen aquí

1.3 Proceso de operación

Insertar descripción de la imagen aquí

Esta imagen es el diagrama de composición de jvm, que se divide en cuatro partes:

  • cargador de clases

    • La función del cargador de clases es cargar archivos de clases en la memoria. Por ejemplo, si escribimos un programa HelloWorld.java, primero usamos el comando javac para compilarlo y generar el archivo de código de bytes HelloWorld.java ¿Cómo podemos ejecutar el archivo .class? Debe utilizar el cargador de clases de medicina para cargar el archivo de código de bytes en la memoria y luego cargar y ejecutar el programa a través de los módulos posteriores de la jvm. ClassLoader solo es responsable de la carga, en cuanto a si se puede ejecutar, no está dentro de su alcance y es responsabilidad del motor de ejecución.
  • motor de ejecución

    • El motor de ejecución, también llamado intérprete, es responsable de interpretar comandos y enviarlos al sistema operativo para su ejecución.
  • interfaz local

    • La función de la interfaz local es integrar diferentes lenguajes de programación para uso de Java. Su intención original es integrar programas C/C++. Cuando nació Java, C/C++ estaba muy extendido. Para afianzarse, debe haber Es una forma inteligente y sabia de llamar al programa C. /C++, por lo que se abre un área especial en la memoria para procesar el código marcado como nativo. El método específico es registrar el método nativo en la pila de métodos nativos y cargar el nativo. bibliotecas cuando se ejecuta el motor de ejecución. En la actualidad, este método se utiliza cada vez menos, excepto para aplicaciones relacionadas con el hardware, como controlar impresoras a través de programas Java o administrar equipos de producción a través de sistemas Java. Es relativamente raro en aplicaciones de nivel empresarial debido a los campos heterogéneos actuales. La comunicación está muy desarrollada, por ejemplo, puede utilizar la comunicación Socket, también puede utilizar el servicio web, etc., no lo presentaré en detalle.
  • Área de datos en tiempo de ejecución

    • Ejecutar el área de datos es el foco de toda la JVM. Todos los programas que escribimos se cargan aquí antes de comenzar a ejecutarse. El ecosistema Java es tan próspero gracias a la excelente autonomía de esta área. Todo el marco JVM carga archivos a través del cargador y luego el ejecutor procesa los datos en la memoria. ¡La interacción con sistemas heterogéneos se puede realizar a través de interfaces locales!

2. Estructura de memoria JVM

2.1 Contador de programas

Insertar descripción de la imagen aquí

2.1.1 Definición

Contador de programa Registro Contador de programa (Registro)

  • El contador del programa es una pequeña área de memoria que puede considerarse como un indicador de número de línea para el hilo actual que ejecuta el código de bytes. En el modelo conceptual de la máquina virtual, el trabajo de interpretación del código de bytes es seleccionar el siguiente paso cambiando el valor de este contador. Las instrucciones de código de bytes ejecutadas.

  • Por ejemplo, el control de bifurcaciones, el control de bucles, los saltos, las excepciones y otras operaciones, la recuperación de subprocesos y otras funciones se completan a través de este contador. Porque el subproceso múltiple de JVM se logra cambiando los subprocesos por turnos y asignando tiempo de ejecución del procesador. Por lo tanto, en un momento dado, un procesador (o núcleo para procesadores multinúcleo) solo ejecutará instrucciones en un hilo.

  • Por lo tanto, para volver a la posición de ejecución correcta después del cambio de hilo, cada hilo necesita su propio contador de programa único. Los contadores de varios hilos no se afectan entre sí y se almacenan de forma independiente. A este tipo de área de memoria la llamamos área de memoria privada de subprocesos.

  • Si el hilo está ejecutando un método Java, este contador registra la dirección de la instrucción de código de bytes de la máquina virtual que se está ejecutando; si se está ejecutando el método nativo, el contador está vacío (indefinido). Esta área de memoria está en la máquina virtual en Java. La única área de memoria que no especifica ningún OutOfMemoryError.

Función , guarda la dirección de la instrucción que se está ejecutando actualmente. Una vez que se ejecuta la instrucción, el contador del programa se actualizará a la siguiente instrucción.

Características

  • es hilo privado
  • sin desbordamiento de memoria

2.2, pila de máquinas virtuales

Insertar descripción de la imagen aquí

2.2.1 Definición

Pilas de máquinas virtuales Java

  • La memoria requerida por cada hilo cuando se ejecuta se llama pila de máquina virtual.

  • Cada pila se compone de múltiples marcos de pila (Marco), correspondientes a la memoria ocupada por cada llamada a método.

  • Cada hilo solo puede tener un marco de pila activo, correspondiente al método que se está ejecutando actualmente.

  • De acuerdo con el contador del programa, la pila de la máquina virtual Java también es privada de subprocesos y tiene el mismo ciclo de vida que el subproceso.

  • La pila de la máquina virtual describe el modelo de memoria de ejecución del método. Cada método crea un marco de pila cuando se ejecuta, que se utiliza para almacenar tablas de variables locales, pilas de operandos, salidas de métodos y otra información. El proceso de cada método desde la ejecución hasta el final corresponde al proceso de un marco de pila desde que se empuja hacia la pila hasta que se saca de la pila.

  • La tabla de variables locales almacena cuatro categorías y ocho tipos de datos básicos conocidos por el compilador. La referencia del objeto (refrence) no es equivalente al objeto en sí. Puede ser un puntero de referencia que apunta a la dirección inicial del objeto.

  • La asignación de memoria de la tabla de variables locales se ha asignado en el momento de la compilación. Las de 64 bits de largo y doble ocuparán dos espacios de variables locales y los tipos de datos restantes solo ocuparán uno. Al ingresar un método, es completamente posible determinar cuánto espacio de memoria necesita asignar este método en la pila. El tamaño de la tabla de variables locales no cambia durante la ejecución del método.

  • Si la profundidad solicitada por el subproceso en la pila es mayor que la profundidad permitida por la máquina virtual, se producirá una excepción StackOverFlowError; si la pila de la máquina virtual se puede expandir dinámicamente (la mayoría de las máquinas virtuales actuales admiten la expansión dinámica y, por supuesto, también permiten pilas de máquinas virtuales de longitud fija), si la extensión no puede solicitar suficiente memoria, se generará una excepción OutOfMemoryError.

análisis del problema

  • ¿Las variables locales dentro de los métodos son seguras para subprocesos?
    • Si no se puede acceder a las variables locales dentro de un método fuera del alcance del método, es seguro para subprocesos.
    • Si una variable local hace referencia a un objeto y escapa del alcance del método, se debe considerar la seguridad del subproceso

2.2.2 Desbordamiento de la memoria de pila

  • Demasiados marcos de pila hacen que la memoria de la pila se desborde
  • El marco de la pila es demasiado grande, lo que provoca que la memoria de la pila se desborde.

2.2.3 Diagnóstico de ejecución de subprocesos

Caso 1: demasiado uso de la CPU

posición

  • Utilice top para localizar qué proceso está ocupando demasiada CPU.
  • ps H -eo pid,tid,%cpu | grep ID de proceso (use el comando ps para localizar mejor qué subproceso está causando el alto uso de CPU)
  • identificación del proceso jstack
    • Puede encontrar el hilo problemático según el ID del hilo y localizar además el número de línea del código fuente del código problemático.

2.2.4 Marco de pila

Composición: tabla de variables locales, pila de operandos, enlace dinámico, dirección de retorno del método

Tabla de variables locales:

Almacene una lista de variables locales;

Una variable local puede guardar datos de tipo booleano, byte, char, short, flotante, referencia y dirección de retorno. Dos variables locales pueden guardar datos de tipo largo y doble;

Las variables locales utilizan índices para posicionar el acceso y el valor del índice de la primera variable local es cero;

Pila de operandos:

También llamada pila de operaciones, es una pila de último en entrar, primero en salir;

Cuando un método recién comienza a ejecutarse, su pila de operandos está vacía. Con la ejecución del método y la ejecución de instrucciones de código de bytes, las constantes o variables se copiarán de la tabla de variables locales o los campos de la instancia del objeto y se escribirán en la pila de operandos. Luego, a medida que avanza el cálculo, los elementos de la pila se colocan en la tabla de variables locales o se devuelven al llamador del método, es decir, la operación de pila/extracción; una ejecución
completa de un método a menudo incluye múltiples procesos de extracción/extracción;

Para entenderlo simplemente, la pila de operandos es la plataforma operativa real del hilo;

Enlace dinámico:

Simplemente entendido como una referencia que apunta al grupo constante de tiempo de ejecución;

En el archivo de clase se describe que un método llama a otros métodos, o el acceso a sus variables miembro está representado por referencias simbólicas. La función del enlace dinámico es convertir los métodos representados por estas referencias simbólicas en referencias directas de métodos reales;

2.3 Pila de métodos locales

Insertar descripción de la imagen aquí

Las funciones y características de la pila de métodos locales son similares a las de la pila de máquinas virtuales y también son privadas de subprocesos.

La diferencia es que el objeto servido por la pila de métodos locales es el método nativo ejecutado por la JVM, mientras que el objeto servido por la pila de la máquina virtual es el método Java ejecutado por la JVM.

¿Cómo servir métodos nativos?
¿Qué idioma se utiliza para implementar el método nativo?
¿Cómo organizar estructuras de datos como marcos de pila para métodos de servicio?
La especificación de la máquina virtual no proporciona disposiciones obligatorias, por lo que se pueden implementar libremente diferentes máquinas virtuales.

2.4 Montón

Insertar descripción de la imagen aquí

2.4.1 Definición

  • Para la mayoría de las aplicaciones, el montón de Java (Java Heap) es el área de memoria más grande administrada por la JVM, y el montón de Java es un área compartida por todos los subprocesos y creada cuando se inicia la máquina virtual.

  • El único propósito de esta área es almacenar objetos de instancia, y casi todas las instancias de objetos asignan espacio aquí. Esto se describe en la especificación JVM: todas las instancias de objetos y matrices deben asignar espacio en el montón.

  • El montón de Java es el área principal administrada por el recolector de basura, por lo que a menudo se le llama montón de GC. Desde la perspectiva de la asignación de memoria, dado que el mecanismo de recolección de basura actual es la recolección de basura generacional, el montón se puede dividir aún más en la generación anterior y la nueva generación, y luego dividirse en el área de Eden y el área de Survivor. dividirse aún más en Se divide en Desde el área de Superviviente y Hasta el área de Superviviente. Según las especificaciones de JVM, el montón de Java puede estar en un espacio de memoria físicamente discontinuo siempre que sea lógicamente continuo.

  • Al igual que nuestro disco, puede ser de tamaño fijo o ampliable. Sin embargo, los principales actuales adoptan estrategias escalables (usando controles -Xmx y -Xms). Si la asignación de memoria no se completa en el montón y no hay espacio de memoria expandible en el montón, se generará una excepción OutOfMemoryError.

Montón

  • A través de la nueva palabra clave, la creación de objetos utilizará memoria de montón.

Características

  • Es compartido por subprocesos y todos los objetos en el montón deben considerar problemas de seguridad de subprocesos.
  • Tiene mecanismo de recolección de basura.

2.4.2 Desbordamiento de memoria del montón

2.4.3 Diagnóstico de memoria del montón

  1. Herramienta jps
    para verificar qué procesos java están en el sistema actual
  2. Herramienta jmap
    para ver el uso de memoria del montón jmap - ID del proceso del montón
  3. La herramienta jconsole
    es una interfaz gráfica y una herramienta de monitoreo multifuncional que puede monitorear continuamente

Caso:
después de la recolección de basura, el uso de memoria sigue siendo alto

2.5 Área del método

Insertar descripción de la imagen aquí

2.5.1 Definición

  • El área de método, al igual que el montón de Java, tiene un área de memoria compartida por cada hilo, que se utiliza para almacenar información de clase, constantes, variables estáticas, código compilado por el compilador en tiempo real y otros datos que han sido cargados por la máquina virtual. .

  • La máquina virtual Java tiene restricciones relativamente flexibles en el área de métodos. Además de no requerir un espacio continuo como el montón y tener la opción de tamaño fijo o capacidad de expansión, también puede optar por no implementar la recolección de basura.

  • Relativamente hablando, la recolección de basura es relativamente rara en esta área, pero eso no significa que los datos puedan sobrevivir permanentemente después de ingresar al área del método. Los objetivos de reciclaje en esta área son principalmente el reciclaje del grupo constante y la descarga de tipos. , esto El desempeño del reciclaje regional es relativamente insatisfactorio. Especialmente para el tipo de desinstalación, las condiciones son bastante duras. Según la especificación de la máquina virtual Java, cuando el área del método no puede cumplir con la asignación de memoria, se generará una excepción OutOfMemoryError.

2.5.2 Composición

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

2.5.3 Desbordamiento de memoria en el área de método

Antes de la versión 1.8, causaría un desbordamiento de la memoria de generación permanente.

* 演示永久代内存溢出 java.lang.OutOfMemoryError: PermGen space
* -XX:MaxPermSize=8m

Después de 1.8, provocará un desbordamiento de la memoria del metaespacio.

* 演示元空间内存溢出 java.lang.OutOfMemoryError: Metaspace
* -XX:MaxMetaspaceSize=8m

2.5.4 Grupo constante de tiempo de ejecución

  • El grupo de constantes es una tabla. Las instrucciones de la máquina virtual utilizan esta tabla de constantes para encontrar el nombre de la clase, el nombre del método, el tipo de parámetro, el literal y otra información que se ejecutará.

  • Grupo constante de tiempo de ejecución, el grupo constante está en el archivo * .class. Cuando se carga la clase, la información del grupo constante se colocará en el grupo constante de tiempo de ejecución y la dirección del símbolo dentro se cambiará a una dirección real.

  • El grupo de constantes de tiempo de ejecución es parte del área de métodos. Además de la versión de la clase, el campo, el método y la información de la interfaz, también hay un grupo de constantes en el archivo de clase. Se utiliza para almacenar referencias a varios literales y símbolos del compilador. Este contenido se almacenará en el grupo constante después de que se cargue la clase.

  • En términos generales, además de guardar las referencias de símbolos descritas en el archivo de clase, las referencias directas traducidas también se almacenan en el grupo constante de tiempo de ejecución. Una de las características más importantes del grupo de constantes en tiempo de ejecución en comparación con el grupo de constantes en el archivo de Clase es su naturaleza dinámica. El lenguaje Java no requiere que se generen constantes durante la compilación. En otras palabras, el contenido del grupo de constantes en la Clase El archivo no se puede ingresar en el grupo de constantes. También es posible colocar constantes recién generadas en el grupo de constantes durante el tiempo de ejecución. La característica más utilizada de esta característica es el método intern() de String. Dado que el grupo de constantes de tiempo de ejecución es parte del área del método, naturalmente tiene las restricciones del área del método, por lo que cuando no se puede solicitar la memoria, se generará una excepción OutOfMemoryError.

2.5.5 Características de StringTable

  • Las cadenas en el grupo constante son solo símbolos y se convierten en objetos cuando se usan por primera vez.
  • Utilice el mecanismo del grupo de cadenas para evitar la creación repetida de objetos de cadena
  • El principio de empalme de variables de cadena es StringBuilder (1.8)
  • El principio del empalme constante de cadenas es la optimización en tiempo de compilación
  • Puede utilizar el método interno para colocar activamente objetos de cadena que aún no están en el grupo de cadenas en el grupo de cadenas.
    • 1.8 Intente colocar este objeto de cadena en el grupo de cadenas. Si existe, no se colocará en él. De lo contrario, se colocará en el grupo de cadenas y se devolverá el objeto en el grupo de cadenas.
    • 1.6 Intente colocar este objeto de cadena en el grupo de cadenas. Si hay uno, no se colocará. De lo contrario, el objeto se copiará y se colocará en el grupo de cadenas, y se devolverá el objeto en el grupo de cadenas.

2.5.6 Ajuste del rendimiento de StringTable

  • Ajustar-XX:StringTableSize=número de depósitos

  • Considere si colocar objetos de cuerda en la piscina.

2.5.7 Memoria directa

La memoria directa no es parte del área de datos de tiempo de ejecución de Jvm, pero esta parte del área de memoria se llama con frecuencia y pueden ocurrir excepciones OutOfMemoryError, por lo que lo discutiremos juntos. Obviamente la memoria directa de la máquina no se verá afectada por la memoria asignada por el montón de Java, pero como es memoria, debe estar limitada por la memoria total de la máquina. Cuando los administradores del servidor configuran los parámetros de la máquina virtual, configurarán -Xmx y otra información de parámetros en función de la memoria real, pero a menudo ignoran la memoria directa. La memoria total de cada área es mayor que el límite de memoria física, lo que genera una excepción OutOfMemoryError durante la expansión dinámica.

2.3 Excepción de desbordamiento de memoria

  • Desbordamiento del montón de Java

  • -Xms20m
    -Xmx20m
    -XX:+HeapDumpOnOutOfMemoryError

  • Desbordamiento de la pila de máquinas virtuales y de la pila de métodos locales

  • desbordamiento de memoria directa

3. Recolección de basura

3.1 Cómo determinar si un objeto se puede reciclar

3.1.1 Método de recuento de referencias

Insertar descripción de la imagen aquí
El algoritmo del contador de referencia se resume simplemente de la siguiente manera: Agregue un contador de referencia al objeto. Siempre que haya una referencia al objeto, el contador + 1. Cuando la referencia expira, el contador - 1. En cualquier momento, cuando el contador 0, el objeto ya no se volverá a citar. Objetivamente hablando, el contador de referencia es simple de implementar y tiene una alta eficiencia de determinación, por lo que es una buena opción en la mayoría de los escenarios. Sin embargo, la JVM convencional actual no utiliza el algoritmo de marca y borrado porque es difícil resolver la situación en la que los objetos se llaman entre sí cíclicamente.

3.1.2 Algoritmo de análisis de accesibilidad

En la implementación principal de los principales lenguajes de programación comerciales (como C #, Java), el análisis de accesibilidad se utiliza para determinar si un objeto está vivo. La idea de este algoritmo es utilizar una serie de objetos que se convierten en "GC Roots". " como punto de partida. , comience a buscar hacia abajo desde estos nodos y el camino recorrido por la búsqueda se convertirá en una cadena de referencia. Cuando un objeto no tiene una cadena de referencia conectada a "GC Roots", demuestra que este objeto no está disponible. Indica que se puede reciclar.

Insertar descripción de la imagen aquí

Como se muestra en la figura, aunque Obj5, Obj6 y Obj7 están relacionados entre sí, no tienen ninguna cadena de referencia a la raíz del GC, por lo que se determina que son objetos que deben reciclarse.

Las raíces de GC (recolector de basura), a menudo llamadas, se refieren específicamente a los objetos del recolector de basura. GC recopilará objetos que no son raíces de GC y a los que no hacen referencia las raíces de GC.

  • En Java, los objetos que se pueden utilizar como GC Roots incluyen los siguientes:

    • Objetos a los que se hace referencia en la pila de la máquina virtual;
    • El objeto al que hace referencia la propiedad estática de la clase en el área de método;
    • El objeto al que hace referencia la constante en el área del método;
    • El objeto al que hace referencia JNI (en términos generales, método nativo) en la pila de métodos nativos;

Insertar descripción de la imagen aquí

3.1.3 Cuatro tipos de referencias

Ya sea el número de referencias determinado por el contador de referencias o la accesibilidad de la cadena de referencia determinada por el análisis de accesibilidad, determinar si el objeto está vivo está relacionado con las referencias.

Antes de JDK1.2, una referencia se definía como cuando un tipo de datos de referencia representa la dirección inicial de otra memoria. Este tipo de datos se llama referencia. Esta definición es muy pura, pero también muy limitada. Un objeto Bajo esta definición, hay Sólo hay dos estados: cotizado y no cotizado. Parece impotente describir algunos objetos que son "insípidos para comer y una lástima desecharlos". Esperamos poder describir este tipo de objeto. Cuando la memoria sea suficiente, guárdela en la memoria. Cuando el espacio de memoria aún sea escaso después de la recolección de basura, esta parte del objeto se puede reciclar. Las funciones de caché de muchos sistemas son adecuados para este tipo de aplicaciones.

Por lo tanto, después de JDK1.2, las referencias se volverán a expandir y dividir en referencias fuertes, referencias suaves, referencias débiles y referencias virtuales. La fuerza de estas cuatro referencias disminuye en orden.

Cita fuerte:

  • Solo cuando todos los objetos de GC Roots no hacen referencia al objeto a través de [referencias fuertes] se puede recolectar basura del objeto.

  • Las referencias fuertes son omnipresentes en el código, similar a Object obj = new Object(). Mientras exista la referencia fuerte, el recolector de basura nunca reciclará el objeto al que se hace referencia.

​Referencia suave :

  • Cuando solo las referencias suaves hacen referencia al objeto, después de la recolección de basura, si la memoria aún es insuficiente, la recolección de basura se iniciará nuevamente para reciclar los objetos de referencia suave.

  • Puede utilizar la cola de referencia para liberar la referencia suave.

  • Las referencias suaves se utilizan para describir algunos objetos que son útiles pero no necesarios. Para los objetos asociados con referencias suaves, cuando ocurre una excepción de desbordamiento de memoria, se reciclarán dos veces mediante la recolección de basura. Si la memoria del sistema aún no es suficiente después de que se completa el reciclaje secundario, se generará una excepción de desbordamiento de memoria. Después de jdk1 y 2, la clase SoftReference se usa para implementar referencias suaves.

​Referencia débil

  • Cuando solo las referencias débiles hacen referencia al objeto, durante la recolección de basura, los objetos de referencia débiles se reciclarán independientemente de si la memoria es suficiente.

  • Puede utilizar la cola de referencias para liberar la referencia débil
    .

  • Las referencias débiles también se utilizan para describir objetos no esenciales, pero su fuerza es más débil que la de las referencias suaves y solo pueden sobrevivir hasta la próxima recolección de basura. Cuando se recolecta basura, independientemente de si la memoria es suficiente, los objetos con referencias débiles deben reciclarse. Después de jdk1.2, la clase WeakReference se usa para implementar referencias débiles

Referencia fantasma :

  • Debe usarse con la cola de referencia, principalmente con ByteBuffer. Cuando el objeto referenciado se recicla, la referencia fantasma se pondrá en cola y el hilo del Controlador de referencia llamará al método relacionado con la referencia fantasma para liberar la memoria directa.

  • La referencia fantasma es el tipo de relación de referencia más débil. El hecho de que un objeto tenga una referencia fantasma no afectará su vida útil en absoluto y es imposible obtener un objeto de instancia a través de una referencia fantasma. El único propósito de establecer una referencia débil para un objeto es recibir una notificación del sistema cuando el objeto se recolecta como basura. Después de Jdk1,2, PhantomReference se usa para implementar referencias virtuales.

Referencia final:

  • No se requiere codificación manual, pero se usa internamente con la cola de referencia. Durante la recolección de basura, la referencia del finalizador se pone en cola (el objeto al que se hace referencia no se ha reciclado temporalmente) y luego el subproceso del Finalizador encuentra el objeto al que se hace referencia a través de la referencia del finalizador y llama a su método de finalización, el objeto al que se hace referencia solo se puede reciclar durante el segundo GC.

¿Vivir o morir?

Incluso en el análisis de accesibilidad, si ninguna cadena de referencia llega a GC Roots, no es "necesario". En este momento, el sujeto se encuentra en libertad condicional, y para ser declarado oficialmente muerto, deberá pasar por el proceso de calificación al menos dos veces.

Si el objeto descubre que no hay una cadena de referencia conectada a GC Roots después del análisis de accesibilidad, se marcará por primera vez y se filtrará una vez. La condición de detección es si el objeto debe ejecutar el método finalize(). Cuando el objeto If el método finalize() no se anula, o la máquina virtual ha llamado al método finalize(), la máquina virtual considera ambos casos como innecesarios para ejecutar el método finalize().

Si se determina que el objeto ejecutará el método finalize(), entonces el objeto se colocará en una cola llamada F-Queue, y luego una máquina virtual lo creará por sí misma y un hilo con una prioridad más baja lo ejecutará. La ejecución aquí significa que el método finalize() se activará, pero no esperará a que finalice su ejecución.

La razón de esto es que si un objeto es muy lento al ejecutar finalize(), o ejecuta un bucle infinito, esto hará que otros objetos en la F-Queue estén esperando, lo que puede causar seriamente el colapso de todo el sistema de recolección de basura. finalize() es la última oportunidad para que el objeto escape de la muerte. Más tarde, el GC marcará el objeto en la cola F dos veces. Si el objeto quiere guardarse en finalize(), solo puede volver a conectarse con cualquiera en el cadena de referencia. El objeto se puede asociar. Por ejemplo, si el objeto en sí (esta palabra clave) se asigna a otras variables miembro u objetos, se eliminará de la colección para ser reciclado cuando se marque por segunda vez. Si hay No hay asociación, es básicamente seguro que será reciclado.

3.2 Algoritmo de recolección de basura

3.2.1 Mark-Sweep (borrado de marcas)

El algoritmo de recopilación más básico es el algoritmo de barrido de marcas y, como su nombre indica, se divide en dos etapas: marcar y borrar. El primer paso es marcar los objetos a reciclar, una vez completado el marcado, todos los objetos marcados se reciclarán de manera uniforme. Cómo marcar se mencionó anteriormente. La razón por la que se dice que es el algoritmo de recolección de basura más básico es que otros algoritmos también se basan en esta idea y mejoran sus deficiencias.

Hay dos problemas principales. El primero es la eficiencia. La eficiencia del marcado y la limpieza no es alta. El segundo es el problema de asignación de espacio. Una vez que se borra la marca, se generará una gran cantidad de espacio de memoria discontinuo. Demasiados fragmentos de espacio pueden hacer que el programa no pueda encontrar suficiente espacio de memoria cuando necesita asignar espacio a objetos más grandes. durante la operación Y debe realizar una recolección de basura con anticipación. Como se muestra en la figura, se generará una gran cantidad de fragmentos de basura, lo que dará como resultado una baja utilización del espacio.

más rápido

Causará fragmentación de la memoria.

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

3.2.2 Mark-Compact (compilación de marcas)

lento

Sin fragmentación de la memoria

El algoritmo de copia realizará más operaciones de copia cuando la proporción de objetos supervivientes sea relativamente alta y la eficiencia será menor. Más importante aún, si no desea desperdiciar el 50% del área, necesita espacio adicional para garantizar la asignación para hacer frente. con la memoria En el caso extremo en el que el 100% de los objetos sobreviven, este algoritmo generalmente no se utiliza en la generación anterior.

De acuerdo con las características de la generación anterior, alguien ha propuesto otro algoritmo de limpieza de marcas. El proceso de marcado es el mismo que el algoritmo de limpieza de marcas, pero los pasos siguientes no son limpiar directamente los objetos reciclables, sino mover todos los supervivientes. objetos a un extremo y luego limpie directamente los objetos fuera del límite. El diagrama esquemático es el siguiente:

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

3.2.3 Copiar

Sin fragmentación de la memoria

Requiere doble espacio de memoria

Para solucionar el problema de eficiencia apareció un algoritmo de recolección llamado copia, que divide la memoria disponible en dos partes de igual tamaño y solo usa una de ellas a la vez, cuando esta área de memoria se agota, los objetos supervivientes serán Cópielo en otra parte de la memoria y luego limpie el espacio utilizado a la vez, de modo que la mitad del área se recupere cada vez y no haya necesidad de considerar la fragmentación y otros problemas al asignar la memoria. En la parte superior del montón, presione Simplemente asigne memoria secuencialmente, lo cual es simple de implementar y eficiente de ejecutar.

Es solo que este enfoque reduce la memoria original a la mitad, lo cual es demasiado caro.

Todas las máquinas virtuales comerciales actuales utilizan este método para reciclar la nueva generación. La investigación especial de IBM muestra que el 98% de los objetos de la nueva generación "viven y mueren", por lo que no es necesario dividir el área de memoria en proporción 1: 1. , pero divida la memoria en un área más grande para Eden y dos áreas más pequeñas para Survivor. Al reciclar, copie los objetos supervivientes en las áreas de Eden y Survivor a otra área de Survivor a la vez, y luego transfiera las áreas de Eden y Survivor. limpieza del tiempo. La proporción predeterminada de Eden a Survivor en el área Hotspot es 8:1, lo que significa que la memoria disponible de la nueva generación es del 90% y solo el 10% de la memoria se dividirá en memoria reservada. Por supuesto, en la mayoría de los casos es del 98%, pero no podemos garantizar que los objetos supervivientes reciclados cada vez sean menos del 10%. Cuando el área de Superviviente no es suficiente, debe confiar en otras áreas para garantizar la asignación. Si la otra área de Superviviente no es suficiente, el objeto puede ingresar directamente a la vejez a través del mecanismo de garantía de memoria.

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

3.3 Recolección de basura generacional

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

  • El objeto se asigna por primera vez en el área del Edén.

  • Cuando el espacio de nueva generación es insuficiente, se activa un gc menor. Los objetos supervivientes de Eden y from se copian a to mediante copia. La edad de los objetos supervivientes aumenta en 1 y se intercambia de a.

  • Un gc menor activará la detención del mundo, suspenderá otros subprocesos de usuario y esperará hasta que se complete la recolección de basura antes de que los subprocesos del usuario reanuden su ejecución.

  • Cuando la vida útil del objeto excede el umbral, se promoverá a la generación anterior, la vida útil máxima es 15 (4 bits)

  • Cuando el espacio de la generación anterior es insuficiente, se activará primero el gc menor. Si el espacio aún es insuficiente más tarde, se activará el gc completo y el tiempo STW será más largo.

Todos los recolectores de basura comerciales actuales utilizan la recolección de basura generacional. Este algoritmo no tiene ideas nuevas. Simplemente divide la memoria en varios bloques de acuerdo con el ciclo de supervivencia del objeto. Generalmente, el montón de Java se divide en la nueva generación y la antigua generación. De esta forma se puede seleccionar el algoritmo de reciclaje más adecuado según las características de los objetos de cada generación. En la nueva generación, una gran cantidad de objetos mueren cada vez que se recolecta basura, y solo una pequeña cantidad de objetos sobrevive, por lo que es adecuado utilizar algoritmos de replicación. La recolección de basura se puede completar con solo un pequeño costo de copia de objetos, sin embargo, debido a que la generación anterior tiene una alta tasa de supervivencia y no hay otras garantías de asignación de memoria, se debe utilizar mark-clean o mark-organize para el reciclaje.

  1. La generación se divide en generación joven y generación anterior. La generación joven se divide en el área de Eden y el área de Survivor. Por lo general, la proporción predeterminada es 8: 1: 1. Solo el 10% del espacio está reservado como área reservada. cada vez, y luego el 90 % del espacio se puede utilizar para nuevos objetos.
  2. Después de cada recolección de basura, la edad del objeto superviviente corresponde a +1. Cuando el objeto sigue vivo después de 15 veces, lo dejamos entrar directamente en la vejez.
  3. Otra forma de ingresar a la generación anterior es el mecanismo de garantía de memoria, es decir, cuando el espacio en la nueva generación no es suficiente, el objeto ingresa directamente a la generación anterior.
  4. La recolección de basura de la nueva generación se llama GC menor y la recolección de basura de la generación anterior se llama GC completo.

3.3.1 Parámetros de VM relacionados

significado parámetro
tamaño inicial del montón -Xms
tamaño máximo del montón -Xmx o -XX:MaxHeapSize=tamaño
Tamaño cenozoico -Xmn 或 (-XX:NewSize=tamaño + -XX:MaxNewSize=tamaño )
Relación de área de supervivencia (dinámica) -XX:InitialSurvivorRatio=ratio y -XX:+UseAdaptiveSizePolicy
Relación de área de supervivencia -XX:SurvivorRatio=cuenta
Umbral de promoción -XX:MaxTenuringThreshold=umbral
Detalles de la promoción -XX:+ImprimirTenenciaDistribución
Detalles de la general -XX:+ImprimirGCDetalles -verbose:gc
Antes de FullGC MenorGC -XX:+BuscarAntes deFullGC

3.4 Recolector de basura

3.4.1 Serie

  • hilo único
  • La memoria del montón es pequeña y adecuada para computadoras personales.
-XX:+UseSerialGC = Serial + SerialOld

Insertar descripción de la imagen aquí

3.4.2 Prioridad de rendimiento

  • subprocesos múltiples
  • Gran memoria dinámica, CPU multinúcleo
  • Deje que el tiempo STW sea el más corto 0,2 0,2 ​​= 0,4 por unidad de tiempo, y la proporción del tiempo de recolección de basura sea la más baja, lo que se denomina alto rendimiento
-XX:+UseParallelGC ~ -XX:+UseParallelOldGC
-XX:+UseAdaptiveSizePolicy
-XX:GCTimeRatio=ratio
-XX:MaxGCPauseMillis=ms
-XX:ParallelGCThreads=n

Insertar descripción de la imagen aquí

3.4.3 Prioridad del tiempo de respuesta

  • subprocesos múltiples
  • Gran memoria dinámica, CPU multinúcleo
  • Intente hacer el tiempo más corto de STW único 0,1 0,1 0,1 0,1 0,1 = 0,5
-XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~ SerialOld
-XX:ParallelGCThreads=n ~ -XX:ConcGCThreads=threads
-XX:CMSInitiatingOccupancyFraction=percent
-XX:+CMSScavengeBeforeRemark

Insertar descripción de la imagen aquí

3.4.4、G1

Definición: basura primero

  • 2004 Artículo publicado
  • Experiencia JDK 2009 6u14
  • Soporte oficial de JDK 7u4 2012
  • 2017 JDK 9 predeterminado

Escena aplicable

  • Preste atención tanto al rendimiento como a la baja latencia. El objetivo de pausa predeterminado es 200 ms.

  • Una memoria de montón muy grande dividirá el montón en múltiples regiones del mismo tamaño.

  • El conjunto es un algoritmo de marcado + clasificación, y las dos áreas son un algoritmo de copia.

Parámetros JVM relacionados

-XX:+UseG1GC
-XX:G1HeapRegionSize=size
-XX:MaxGCPauseMillis=time

3.4.4.1, etapa de recolección de basura G1

Insertar descripción de la imagen aquí

3.4.4.2 、 Colección joven

  • Sociedad STW (parar el mundo)

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

3.4.4.3、Colección Joven + CM

  • El marcado inicial de GC Root se realizará durante Young GC.
  • Cuando la proporción de espacio de almacenamiento dinámico ocupado por la generación anterior alcanza el umbral, se realizará un marcado concurrente (sin STW), que está determinado por los siguientes parámetros de JVM.
XX:InitiatingHeapOccupancyPercent=percent (默认45%)

Insertar descripción de la imagen aquí

3.4.4.4 、 Colección mixta

Se realizará recolección integral de basura en las calles E, S y O

  • La nota final (Observación) será STW.
  • La supervivencia de la copia (evacuación) será STW
-XX:MaxGCPauseMillis=ms

Insertar descripción de la imagen aquí

3.4.4.5、 GC completo

  • SerieGC

    • Recolección de basura que ocurre debido a memoria insuficiente en la nueva generación - gc menor
    • Recolección de basura que ocurre debido a memoria insuficiente en la generación anterior - gc completo
  • ParaleloGC

    • Recolección de basura que ocurre debido a memoria insuficiente en la nueva generación - gc menor
    • Recolección de basura que ocurre debido a memoria insuficiente en la generación anterior - gc completo
  • CMS

    • Recolección de basura que ocurre debido a memoria insuficiente en la nueva generación - gc menor
    • Memoria insuficiente en la vieja generación.
  • G1

    • Recolección de basura que ocurre debido a memoria insuficiente en la nueva generación - gc menor
    • Memoria insuficiente en la vieja generación.

3.4.4.6, referencia intergeneracional de la Colección Young

Referencias intergeneracionales en el problema del reciclaje de nueva generación (la vieja generación se refiere a la nueva generación)
Insertar descripción de la imagen aquí

  • Lista de cartas y conjunto recordado
  • Pasar la barrera posterior a la escritura + cola de tarjetas sucias cuando cambia la referencia
  • subprocesos de refinamiento concurrentes 更新 Conjunto recordado

Insertar descripción de la imagen aquí

3.4.4.7、Observación

barrera de preescritura + satb_mark_queue

Insertar descripción de la imagen aquí

3.4.4.8, deduplicación de cadenas JDK 8u20

  • Ventajas: ahorra mucha memoria

  • Desventajas: se ocupa un poco más de tiempo de CPU y el tiempo de reciclaje de nueva generación aumenta ligeramente.

-XX:+UseStringDeduplication
String s1 = new String("hello"); // char[]{'h','e','l','l','o'}
String s2 = new String("hello"); // char[]{'h','e','l','l','o'}
  • Coloque todas las cadenas recién asignadas en una cola
  • Cuando se recicla la nueva generación, G1 verifica simultáneamente si hay cadenas duplicadas
  • Si tienen el mismo valor, déjelos hacer referencia al mismo char[]
  • Tenga en cuenta que esto no es lo mismo que String.intern()
    • String.intern() se centra en objetos de cadena
    • El foco de la deduplicación de cadenas es char[]
    • Dentro de la JVM, se utilizan diferentes tablas de cadenas.

3.4.4.9, desinstalación simultánea de clase de marca JDK 8u40

Después de que todos los objetos estén marcados para concurrencia, podrá saber qué clases ya no se usan. Cuando todas las clases de un cargador de clases ya no se usan, todas las clases cargadas por él se descargan.

-XX:+ClassUnloadingWithConcurrentMark 默认启用

3.4.4.10, JDK 8u60 recicla objetos gigantes

  • Cuando un objeto mide más de la mitad de una región, se le llama objeto gigante.
  • G1 no copia objetos grandes
  • Priorizado para el reciclaje
  • G1 rastreará todas las referencias entrantes de la generación anterior, de modo que los objetos gigantes con una referencia entrante de 0 en la generación anterior puedan eliminarse durante la recolección de basura de la nueva generación.

3.4.4.11 Ajuste del tiempo de inicio de marcas concurrentes en JDK 9

  • El marcado concurrente debe completarse antes de que se llene el espacio del montón; de lo contrario, degenerará en FullGC.
  • Antes de JDK 9, era necesario utilizar -XX:InitiatingHeapOccupancyPercent
  • JDK 9 se puede ajustar dinámicamente
    • -XX:InitiatingHeapOccupancyPercent se utiliza para establecer el valor inicial
    • Muestreo de datos y ajuste dinámico
    • siempre agrega una brecha segura

3.5 Ajuste de la recolección de basura

Conocimientos preliminares

  • Domine los parámetros de VM relacionados con GC y conozca el ajuste básico del espacio
  • Dominar las herramientas relevantes.
  • Comprenda una cosa: el ajuste está relacionado con la aplicación y el entorno, y no existe una regla única para todos.

3.5.1 Áreas de sintonización

  • Memoria
  • contención de bloqueo
  • uso de CPU
  • yo

3.5.2 Determinar objetivos

  • [Baja latencia] o [Alto rendimiento], elija el recopilador adecuado
  • CMS, G1, ZGC
  • ParaleloGC
  • Gusto

3.5.3 El GC más rápido

La respuesta es que no se produce GC.

Verifique el uso de memoria antes y después de FullGC y considere las siguientes preguntas:

  • ¿Hay demasiados datos?

    • resultSet = state.executeQuery(“seleccionar * de 大表 límite n”)
  • ¿La representación de datos está demasiado inflada?

    • gráfico de objetos
    • Tamaño del objeto 16 Entero 24 int 4
  • ¿Hay una pérdida de memoria?

    • mapa estático mapa =
    • suave
    • débil
    • Implementación de caché de terceros

3.5.4 Tuning de nueva generación

Características de la nueva generación.

  • Todas las operaciones nuevas son muy económicas para asignar memoria.
    • Búfer de asignación local de subprocesos TLAB
  • El coste del reciclaje de objetos muertos es cero.
  • La mayoría de los objetos mueren inmediatamente después de su uso.
  • El tiempo de Minor GC es mucho menor que el de Full GC

¿Es más grande mejor?

-Xmn
Sets the initial and maximum size (in bytes) of the heap for the young generation (nursery). GC is
performed in this region more often than in other regions. If the size for the young generation is
too small, then a lot of minor garbage collections are performed. If the size is too large, then only
full garbage collections are performed, which can take a long time to complete. Oracle
recommends that you keep the size for the young generation greater than 25% and less than
50% of the overall heap size.
  • La nueva generación puede acomodar todos los datos [concurrencia * (solicitud-respuesta)]
  • El área de supervivencia es lo suficientemente grande como para retener [objetos actualmente activos + objetos que deben promocionarse]
  • Configure correctamente el umbral de promoción para promocionar objetos de larga duración lo más rápido posible
-XX:MaxTenuringThreshold=threshold
-XX:+PrintTenuringDistribution
Desired survivor size 48286924 bytes, new threshold 10 (max 10)
- age 1: 28992024 bytes, 28992024 total
- age 2: 1366864 bytes, 30358888 total
- age 3: 1425912 bytes, 31784800 total
...

3.5.5 Tuning de vieja generación

Tome CMS como ejemplo

  • Cuanto mayor sea la memoria de antigua generación del CMS, mejor.
  • Intente no sintonizar primero, si no hay GC completo, entonces..., de lo contrario intente sintonizar la nueva generación primero.
  • Observe el uso de la memoria de la generación anterior cuando se produce GC completo y aumente la memoria predeterminada de la generación anterior en 1/4 ~ 1/3.
-XX:CMSInitiatingOccupancyFraction=percent

3.6 Recolector de basura

3.6.1 Recolector en serie

El recolector en serie es el recolector más básico y de mayor desarrollo. Antes de JDK1.3.1, era la única opción para la nueva generación de recolección de basura de máquinas virtuales. Este recopilador es de un solo subproceso. El significado de su único subproceso no solo significa que solo usará una CPU o un subproceso de recolección para completar el trabajo de recolección, lo más importante es que cuando realiza la recolección de basura, otros subprocesos de trabajo se pausarán hasta que se complete la recolección. Este trabajo lo inicia y ejecuta automáticamente la máquina virtual en segundo plano, y todos los subprocesos de trabajo se detienen sin que sean visibles para el usuario, lo que resulta intolerable para muchas aplicaciones. ¿Podemos imaginar lo que sucede cuando nuestra computadora se detiene durante 5 minutos después de funcionar durante 1 hora? Respecto a este diseño, los diseñadores de la máquina virtual también expresaron su malestar, porque es imposible recolectar al mismo tiempo y aquí se generan constantemente objetos basura que no se pueden limpiar por completo.

Entonces, desde 1.3 hasta ahora, el equipo de desarrollo de máquinas virtuales ha estado trabajando arduamente para reducir las pausas de subprocesos causadas por la recolección de basura. Las máquinas virtuales que han surgido son cada vez mejores, pero hasta ahora no se han eliminado por completo.

En este punto, parece que el recolector en serie ya es "una pérdida de tiempo y una lástima abandonarlo", pero de hecho, sigue siendo el recolector de basura predeterminado para la nueva generación de máquinas virtuales en modo Cliente. Tiene ventajas sobre otros recolectores de basura. Por ejemplo, dado que no hay gastos generales al cambiar entre subprocesos, concentrarse en la recolección de basura puede producir naturalmente la mayor eficiencia de utilización de subprocesos. En el contexto de las aplicaciones de escritorio del usuario, la memoria asignada a las máquinas virtuales generalmente no es demasiado grande. Cuando se recopilan objetos de nueva generación de decenas de megabytes o de cien a doscientos megabytes, el tiempo de pausa se puede controlar entre decenas de milisegundos y cien milisegundos. Esto es aceptable siempre y cuando no suceda con frecuencia. Por lo tanto, el recopilador en serie en modo Cliente sigue siendo una buena opción para la nueva generación.

Insertar descripción de la imagen aquí

3.6.2, colector ParNew

El recolector ParNew es en realidad una versión de subprocesos múltiples del recolector en serie. Además de utilizar subprocesos múltiples para la recolección de basura, otros parámetros controlables, algoritmos de recolección, detención de subprocesos de trabajo, principios de asignación de objetos, estrategias de reciclaje, etc., son completamente consistentes. con el coleccionista en serie.

Aparte de la recolección de basura de subprocesos múltiples, no hay mucha innovación, pero de hecho es el recolector de máquinas virtuales preferido para la nueva generación en modo Servidor. Una de las razones importantes es que, excepto el recopilador en serie, es el único que se puede utilizar con CMS. Durante el período JDK 1.5, HotSpot lanzó CMS, un recolector de época para aplicaciones fuertemente interactivas. Este recolector fue el primer recolector verdaderamente concurrente de HotSpot y por primera vez realizó la recolección de basura y los subprocesos de trabajo trabajando al mismo tiempo. posibilidad, en En otras palabras, puedes contaminar y recolectar al mismo tiempo.

Sin embargo, CMS, como recolector de basura de antigua generación, no se puede utilizar con el último recolector de basura de nueva generación lanzado en 1.4, sino que solo se puede utilizar uno de Serial o Parnew. Se puede forzar al recopilador ParNew a especificarlo usando -XX:+UseParNewGC, o al recopilador predeterminado de nueva generación usando la opción -XX:+UseConcMarkSweepGC.

El recolector ParNew nunca tendrá un mejor efecto que el recolector Serial en un entorno de una sola CPU, o incluso mejor que la sobrecarga de interacción de subprocesos. Este recolector no puede garantizar que supere al 100% en el entorno de dos CPU implementadas mediante tecnología Hyper-Threading. . Por supuesto, a medida que aumenta la cantidad de CPU, sigue siendo muy beneficioso para la utilización eficaz de los recursos del sistema durante la GC. Cuando hay muchas CPU, puede usar -XX:ParallelGCThreads para limitar la cantidad de subprocesos de recolección de basura.

Insertar descripción de la imagen aquí

3.6.3, recopilador de recuperación paralela

El recolector Parallel Scavenge es un recolector de nueva generación que utiliza un algoritmo de copia y es un recolector de basura paralelo de subprocesos múltiples. Su enfoque es diferente al de otros recolectores: el enfoque de los recolectores como CMS es acortar el tiempo en que los subprocesos del usuario se detienen durante la recolección de basura, mientras que el recolector Parallel Scavenge es lograr un rendimiento controlable, el llamado rendimiento. relación entre el tiempo que la CPU ejecuta los subprocesos del usuario y el tiempo total de ejecución de la CPU, es decir, rendimiento = (tiempo de trabajo del subproceso del usuario) / (tiempo de trabajo del subproceso del usuario + tiempo de recolección de basura). Por ejemplo, la máquina virtual se ejecuta durante un total de 100 minutos y la recolección de basura consume 1 minuto. , El rendimiento es del 99%. Cuanto más corto sea el tiempo de pausa, más adecuado será para los programas que interactúan con los usuarios. Una buena velocidad de respuesta puede mejorar la experiencia del usuario, pero un alto rendimiento puede utilizar eficientemente el tiempo de la CPU y completar las tareas informáticas del programa lo más rápido posible. Es principalmente adecuado para operaciones en segundo plano sin la necesidad de demasiados programas interactivos.

Hay dos parámetros para controlar el rendimiento, que son el tiempo máximo de recolección de basura: -XX: MaxGCPauseMills, y establece directamente el tamaño del rendimiento: -XX: GCTimeRatio

-XX:+Utilizar política de tamaño adaptable

La estrategia adaptativa también es un punto importante que distingue al recolector Parallel Scavenge del recolector Parnew.

3.6.4, Recolector de serie antiguo

El recopilador Serial Old es la versión anterior del recopilador Serial. También es un recopilador de un solo subproceso que utiliza un algoritmo de clasificación de marcas. El propósito principal de este recopilador también es usarse en modo Cliente. Si está en modo Servidor, hay dos usos: uno se usa junto con el recopilador Parallel Scavenge en versiones anteriores a jdk5 y el otro se usa como solución de respaldo para CMS cuando ocurre una falla del modo concurrente en la recopilación concurrente.

3.6.5, recopilador antiguo paralelo

El recopilador Parallel Old es la versión antigua del recopilador Parallel Scavenge. Utiliza algoritmos de subprocesos múltiples y de clasificación de marcas. Este recopilador solo comenzó a usarse en jdk6. Antes de eso, el recopilador Parallel Scavenge había estado en una etapa incómoda porque De, si la nueva generación adopta el recolector Parallel Scavenge, entonces la generación anterior no tiene más remedio que Serial Old. Debido al arrastre de Serial en la generación anterior en el lado del servidor, es posible que el uso del recolector Parallel Scavenge no logre el efecto. de maximizar el rendimiento., dado que la generación anterior de un solo subproceso no puede utilizar completamente la potencia de procesamiento de la CPU múltiple del servidor, en un entorno donde la generación anterior es grande y el hardware es relativamente avanzado, el rendimiento de esta combinación no es ni siquiera tan bueno como el recopilador Parallel Scavenge + CMS. Hasta la aparición del recopilador Parallel Old, el "recolector de prioridad de rendimiento" finalmente tenía una verdadera combinación. En situaciones donde la prioridad de rendimiento y la sensibilidad de los recursos de la CPU son importantes, se puede utilizar el recopilador Parallel Scavenge + el recopilador Parallel Old.

Insertar descripción de la imagen aquí

3.6.6, recopilador CMS

El recopilador CMS es un recopilador que tiene como objetivo obtener el menor tiempo de pausa. Como puede verse por el nombre (Concurrent Mark Sweep), el algoritmo de eliminación de marcas utilizado se divide en cuatro pasos:

Sólo la marca y el comentario iniciales requieren pausar el hilo del usuario.

  1. Marca inicial: asociar solo objetos con los que GC Roots pueda asociarse directamente, muy rápido

  2. Marcado concurrente: el proceso de GC Roots Tracing,

  3. Observación: para corregir el registro de marca de esa parte del objeto que se cambió debido a la operación del programa de usuario durante la marca concurrente.

  4. purga concurrente

Insertar descripción de la imagen aquí

Dado que los recolectores de procesos de marcado y borrado concurrentes, que toman más tiempo en todo el proceso, pueden trabajar junto con el hilo del usuario, en general, el proceso de reciclaje de memoria CMS se ejecuta al mismo tiempo que el hilo del usuario.

Tres desventajas principales del recopilador CMS:

  1. El recopilador de CMS es muy sensible a los recursos de la CPU
  2. No puedo manejar basura flotante
  3. Debido a que se basa en el algoritmo de eliminación de marcas, se generará una gran cantidad de fragmentos de basura -XX:+UseCMSCompactAtFullCollection

3.6.7, colector G1

En primer lugar, el principio de diseño de G1 es un ajuste de rendimiento simple y factible.

-XX:+UsarG1GC -Xmx32g -XX:MaxGCPauseMillis=200

Entre ellos, -XX:+UseG1GC es para habilitar el recolector de basura G1, -Xmx32g diseña la memoria máxima de la memoria del montón en 32G y -XX:MaxGCPauseMillis=200 establece el tiempo de pausa máximo de GC en 200ms. Si necesitamos sintonizar, cuando el tamaño de la memoria es cierto, solo necesitamos modificar el tiempo máximo de pausa.

  1. asignación de memoria

  2. Recolección de basura joven

  3. Recolección de basura mixta

Insertar descripción de la imagen aquí

Parámetros de configuración comunes:
Insertar descripción de la imagen aquí

4. Herramientas de resolución de problemas y monitoreo del rendimiento de la máquina virtual

4.1 Herramienta Jconsole

Comando de la herramienta jmap: jmap -dump:live,format=b,file=heap.bin 4308

Jconsole es una herramienta de gestión y seguimiento visual basada en JMX.

  1. El directorio donde se encuentra Jsonsole

Insertar descripción de la imagen aquí

Se puede ver en el directorio bin de jdk y luego hacer doble clic en él para abrir la interfaz de monitoreo. Después de ingresar, podemos ver esta interfaz. La pestaña de descripción general es principalmente una descripción general de los principales datos de ejecución de la máquina virtual. Hay cuatro gráficos, a saber, montón, subproceso, clase y ocupación de CPU. La pestaña de memoria se utiliza para monitorear la tendencia cambiante de la memoria de la máquina virtual (montón de Java y generación permanente) administrada por el recopilador.

Insertar descripción de la imagen aquí

4.2 Herramienta Jprofiler

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/shuai_h/article/details/131031243
Recomendado
Clasificación