Conocimiento profundo de la compilación y optimización de back-end jvm

Este artículo es una nota de lectura.

1. Compilador justo a tiempo

Código de
punto de acceso Un método o bloque de código se ejecuta con especial frecuencia (recursivamente). Estos códigos se denominan códigos de punto de acceso
. Un compilador de fondo que compila el código de punto de acceso en código local se llama compilador justo a tiempo.

Varias preguntas planteadas alrededor del comienzo del artículo:

1. ¿Por qué la máquina virtual HotSpot utiliza una arquitectura en la que coexisten un intérprete y un compilador en tiempo real?

  • Cuando el programa necesita iniciarse y ejecutarse rápidamente, el intérprete puede desempeñar un papel primero, ahorrar tiempo de compilación y ejecutarse de inmediato.
  • Después de que el programa comienza, a medida que pasa el tiempo, el compilador juega un papel gradualmente, compilando más y más código en código local, lo que puede reducir la pérdida intermedia del intérprete y obtener una mayor eficiencia de ejecución. Cuando el límite de recursos de memoria es grande en el entorno de ejecución del programa, puede usar la ejecución interpretada para ahorrar memoria
  • Los intérpretes y compiladores a menudo trabajan juntos para complementarse
    Inserte la descripción de la imagen aquí

2. ¿Por qué la máquina virtual HotSpot implementa dos (o tres) compiladores en tiempo real diferentes?
Principalmente para la compilación jerárquica.
Cuando la compilación jerárquica, el intérprete, el compilador del cliente y el compilador del servidor funcionarán al mismo tiempo, el código dinámico puede compilarse varias veces, use el compilador del cliente para obtener una compilación más alta Velocidad, use el compilador del lado del servidor para obtener una mejor calidad de compilación, y no es necesario que realice la tarea adicional de recopilar información de monitoreo del rendimiento al interpretar y ejecutar, y cuando el compilador del lado del servidor usa un algoritmo de optimización de alta complejidad, el compilador del lado del cliente Puede usar una optimización simple para obtener más tiempo de compilación.

3. ¿Cuándo se ejecuta el programa usando el intérprete? ¿Cuándo usar el compilador para ejecutar?
Inserte la descripción de la imagen aquí

4. ¿Qué código de programa se compilará en código local? ¿Cómo compilar el código local?
· Un método que se llama varias veces. · Cuerpo de bucle que se ejecuta varias veces.

El objeto de destino de la compilación es el cuerpo del método completo, no un cuerpo de bucle separado.

En el primer caso, dado que se basa en la compilación activada por el método, el compilador tomará naturalmente el método completo como el objeto de compilación. Esta compilación también es el método estándar de compilación justo a tiempo en la máquina virtual.

En el último caso, aunque la acción de compilación es activada por el cuerpo del bucle y el punto de acceso es solo una parte del método, el compilador aún debe usar todo el método como el objeto de compilación, solo la entrada de ejecución (a partir de las pocas instrucciones de código de bytes del método Ejecución) será ligeramente diferente, y el número de código de byte (Índice de código de byte, BCI) del punto de entrada de ejecución se pasará durante la compilación. Este método de compilación se llama "On Stack Replacement" (OSR) porque la compilación ocurre durante la ejecución del método. Es decir, el marco de la pila del método todavía está en la pila, y el método se reemplaza.

5. ¿Cómo observar el proceso de compilación y el resultado de la compilación del compilador justo a tiempo desde el exterior?

Algunos parámetros de ejecución requieren que se admitan las máquinas virtuales HotDepug de nivel de optimización FastDebug o SlowDebug. Las máquinas virtuales de nivel de producto no pueden usar estos parámetros.
Es decir, la persona promedio no puede observar la
compilación a mano, o la versión de compilación no oficial

2. Compilador avanzado

Una rama es similar a los compiladores tradicionales de C y C ++, que compila el código del programa en el trabajo de traducción estática del código de máquina antes de que se ejecute el programa;

La otra rama es precompilar y guardar el trabajo de compilación que el compilador original justo a tiempo necesita hacer en tiempo de ejecución. La próxima vez que se ejecute en estos códigos (como el código de biblioteca común es utilizado por otros procesos Java en la misma máquina), se carga directamente Entra y úsalo.

Se puede ver que el ejemplo del brote de Android es el uso perfecto de la compilación temprana

3. Tecnología de optimización.

La tecnología de optimización del compilador
presenta principalmente cuatro tipos: 1. Optimización técnica final: integración de métodos 2. La tecnología de optimización más avanzada: análisis de escape 3. Tecnología de optimización clásica independiente del lenguaje: eliminación de subexpresiones comunes 4. Optimización clásica relacionada con el lenguaje Tecnología: Eliminación de verificación de límites de matriz.
Método en línea: El
método en línea consiste en "copiar" el código del método de destino al método que inició la llamada intacto, evitando la invocación real del método.
Para el método de Java, la dificultad es que muchos métodos son métodos virtuales, y la selección polimórfica de la llamada no se conoce antes de ejecutarse. Para resolver este problema, la máquina virtual de Java introduce un método llamado análisis de herencia de tipos (CHA). Se utilizan diferentes métodos en diferentes situaciones:
① Si es un método no virtual, solo en línea.
②Si es un método virtual y este método solo tiene una versión de destino para ser seleccionada en el estado actual del programa, puede ser "guardado en línea" asumiendo. Debido a que el nuevo tipo puede cargarse en el futuro, lo que cambiará la conclusión de CHA, esta alineación es una optimización predictiva radical, y la "puerta de escape" debe reservarse.
③Si es un método virtual y hay varias versiones para elegir, el caché en línea se usará para reducir el costo de la invocación del método, que puede entenderse como el registro de la invocación de cada método de diferentes versiones, y solo necesita juzgar el método después de la próxima llamada La versión adoptada se puede incluir de inmediato.
Análisis de escape:
este no es un medio para optimizar directamente el código, sino una técnica de análisis que proporciona una base para otras medidas de optimización.
Cuando un objeto se define en un método, puede ser referenciado por un método externo. Este método se llama escape de método e incluso se accede a él por hilos externos. Esto se llama escape de hilo. De no escape a escape de método a escape de hilo se denomina diferentes niveles de escape de objeto de menor a mayor.
Si un objeto no escapa o la probabilidad de escape es extremadamente baja, puede hacer la siguiente optimización:
① Asignación en la pila: deje que este objeto no asigne memoria en el montón de Java, asigne memoria directamente en la pila, el espacio de memoria ocupado por el objeto puede El marco de la pila aparece y se destruye.
Replacement Reemplazo escalar: los datos no pueden descomponerse en datos más pequeños para representar, entonces este es un escalar, de lo contrario es un agregado. El objeto es una cantidad agregada típica. Si el objeto no se escapa, se puede desmontar y sus variables miembro se pueden restaurar al tipo original para acceder según la situación de acceso al programa.
③ Eliminación de sincronización: otros subprocesos no accederán sin escapar, por lo que las medidas de sincronización de esta variable se pueden cancelar.
Eliminación de subexpresión común:
para las variables que se han calculado, el resultado se puede invocar en llamadas posteriores y se elimina la expresión de la variable.
Si esta optimización se limita a los bloques básicos del programa, puede llamarse eliminación de subexpresión común local; el alcance de la optimización cubre múltiples bloques básicos, que pueden llamarse eliminación de subexpresión común global.
La verificación de límites de datos elimina que
Java es un lenguaje de seguridad dinámico. Cada vez que accede a los datos, debe verificar los límites superior e inferior, pero cada verificación debe perder mucho tiempo de ejecución. Por lo tanto, se utiliza el manejo de excepciones implícito y la verificación solo se realiza cuando se produce un error.

Publicado 37 artículos originales · ganado elogios 6 · vistas 4638

Supongo que te gusta

Origin blog.csdn.net/littlewhitevg/article/details/105567500
Recomendado
Clasificación