Conocimiento profundo de jvm-stack frame y llamada al método

Este artículo es una nota de lectura.

1. Conceptos básicos

Inserte la descripción de la imagen aquí
La máquina virtual Java utiliza métodos como la unidad de ejecución más básica . "Stack Frame" es una estructura de datos utilizada para admitir la invocación y ejecución de métodos de la máquina virtual. También es la máquina virtual en el área de datos del tiempo de ejecución de la máquina virtual. Elemento de pila de la pila de máquina virtual.

** Composición básica: ** Tabla de variables locales, pila de operandos, enlace dinámico, dirección de retorno del método y alguna información adicional adicional.

Al compilar el código fuente del programa Java , cuánta tabla de variables locales se necesita en el marco de la pila, qué tan profundo debe analizarse y calcularse la pila de operandos, y escribirse en la propiedad Código de la tabla de métodos

Desde la perspectiva de un programa Java, todos los métodos en la pila de llamadas están en el mismo estado al mismo tiempo y en el mismo hilo. Para el motor de ejecución, en el subproceso activo, solo se está ejecutando el método en la parte superior de la pila , y solo el marco de la pila en la parte superior de la pila es efectivo , lo que se llama ** "marco de pila actual" ** ( CurrentStack Frame), el método asociado con este marco de pila se denomina "Método actual".

Hay una parte en el código fuente de springboot:

Esta parte está en el método de construcción de SpringApplication.class, la clase que obtiene la entrada del método principal, su operación es obtener el marco de pila actual; la depuración puede ver claramente que el
Inserte la descripción de la imagen aquí
proceso básico del marco de pila actual es crear una excepción de tiempo de ejecución y luego obtener la matriz de pila, atravesar StackTraceElement, juzgue si el nombre del método es "mian", en caso afirmativo, cree un objeto Class por el método Class.forName ().

El código es muy simple, pero el uso de SpringBoot nos hace sentir muy esclarecedores. Comparemos el manejo de excepciones de Java y aprendamos más sobre el uso de StackTrace.

Stacktrace (seguimiento de pila) es una herramienta de depuración muy útil. Cuando se produce una excepción en el programa o se lanza manualmente una excepción, se puede mostrar el lugar del error, causando la relación jerárquica del error.

2. Tabla de variables locales

Espacio de almacenamiento para almacenar parámetros del método y variables locales definidas dentro del método.
Cuando el programa Java se compila en un archivo de clase, la capacidad máxima de la tabla de variables locales que el método necesita asignar se determina en el elemento de datos max_locals del atributo Code del método.

Para booleano de 32 bits, byte, char, short, int, float, reference [illustration] y returnAddress, una ranura es suficiente.
Para los tipos de datos de 64 bits, la máquina virtual Java asigna dos espacios de ranuras variables consecutivas de manera alineada con bits altos.

La máquina virtual Java utiliza la tabla de variables locales a través del posicionamiento del índice . ** El rango de valores del índice es de 0 al número máximo de ranuras de variables en la tabla de variables locales. ** Si está accediendo a una variable del tipo de datos de 32 bits, el índice N representa el uso de la ranura de la variable N. Si está accediendo a una variable del tipo de datos de 64 bits, significa que se utilizarán las variables Nth y N + 1. Tragamonedas

Cuando se llama a un método, la máquina virtual Java utiliza la tabla de variables locales para completar el proceso de transferencia del valor del parámetro a la lista de variables del parámetro, es decir, la transferencia del parámetro real al parámetro formal.

El intervalo de variables en la tabla de variables locales es reutilizable
Ejemplo de reutilización:
Inserte la descripción de la imagen aquí
si no hay int a = 0; gc no se activará y gc se activará después de que esté disponible;
razón:
si el intervalo de variables en la tabla de variables local todavía tiene alguna información Referencia de objeto de matriz de marcador de posición. En la primera modificación, aunque el código ha salido del alcance del marcador de posición, pero después de esto, no se han producido operaciones de lectura o escritura en la tabla de variables locales, el espacio de variables originalmente ocupado por el marcador de posición no ha sido reutilizado por otras variables Por lo tanto, la tabla de variables locales como parte de GC Roots aún mantiene su asociación.

3. Pila de operandos

La pila de operandos (pila de operandos) a menudo se llama la pila de operaciones, que es una pila de último en entrar, primero en salir (último en entrar, primero en salir, LIFO).

Cada elemento de la pila de operandos puede ser cualquier tipo de datos Java, incluidos long y double. La capacidad de pila ocupada por el tipo de datos de 32 bits es 1, y la capacidad de pila ocupada por el tipo de datos de 64 bits es 2.

4. Conexión dinámica

Cada marco de pila contiene una referencia al método al que pertenece el marco de pila en el grupo constante de tiempo de ejecución [ilustración]. Esta referencia se mantiene para admitir la conexión dinámica durante la invocación del método.

5. Dirección de devolución del método

Solo hay dos maneras de salir del método: 1. devolver normalmente y devolver el valor a la persona que llama 2. lanzar una excepción y la excepción no se maneja adecuadamente.
En términos generales, cuando el método sale normalmente, el valor del contador de PC del método de llamada puede usarse como el retorno Dirección, es probable que el contador de pila guarde este valor de contador. Cuando el método sale anormalmente, la dirección de retorno está determinada por la tabla del controlador de excepciones, y esta parte de la información generalmente no se guarda en el marco de la pila.
Las operaciones posibles al salir son: restaurar la tabla de variables locales y la pila de operandos del método superior, empujar el valor de retorno (si lo hay) en la pila de operandos del marco de la pila de la persona que llama, ajustar el valor del contador de la PC para apuntar a la llamada al método Una instrucción después de la instrucción, etc.

6. Información adicional

Información relacionada con la depuración y la recopilación de rendimiento. Esta parte de la información depende completamente de la implementación específica de la máquina virtual.
En general, las conexiones dinámicas, las direcciones de retorno de métodos y otra información adicional se agrupan, denominadas información de marco de pila.

Ejemplo: i ++, ++ i

También se llama ejecución de interpretación basada en pila

int a = 10;
 int b = a++ + ++a + a--; 
 System.out.println(a); 
 System.out.println(b);

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
La imagen proviene del descifrado del caballo oscuro de la estación b jvm

7. Llamada de método

El proceso de compilación del archivo Class no incluye los pasos de conexión de la compilación del lenguaje de programación tradicional. Todas las llamadas a métodos almacenadas en el archivo Class son solo referencias simbólicas, no la dirección de entrada del método en el diseño de memoria de tiempo de ejecución real (es decir, el directo Referencia).

La máquina virtual Java admite los siguientes cinco métodos para llamar a instrucciones de bytecode, a saber: invokestatic. Se usa para llamar a métodos estáticos.

· Invokespecial. Se utiliza para llamar al constructor de instancias <init> (), métodos privados y métodos en la clase padre.

· Invokevirtual. Se usa para llamar a todos los métodos virtuales.

· Invocar interfaz. Se usa para llamar a métodos de interfaz, y un objeto que implementa la interfaz se determinará en tiempo de ejecución.

· Invocado dinámicamente. El método al que hace referencia el calificador del punto de llamada se resuelve dinámicamente en tiempo de ejecución y luego se ejecuta el método. La lógica de despacho de las primeras 4 instrucciones de llamada se fija en la máquina virtual Java, y la lógica de despacho de la instrucción invocada dinámica se determina por el método de arranque establecido por el usuario.

Mientras los métodos que pueden invocar las instrucciones invokestatic e invookespecial, la única versión de llamada se pueda determinar durante la fase de análisis, existen cuatro métodos en el lenguaje Java que cumplen esta condición: métodos estáticos, métodos privados, constructores de instancias y métodos de superclase, más El método modificado por final (aunque se invoca utilizando la instrucción invokevirtual) , estas cinco llamadas al método resolverán las referencias de símbolos en referencias directas al método cuando se carga la clase . Estos métodos se denominan colectivamente "Métodos no virtuales". Por el contrario, otros métodos se denominan "Métodos virtuales".

Despacho

Man man = new Women ();
Man es de tipo estático, Women es de tipo dinámico;

Por lo tanto, la ejecución de un método se divide en despacho estático y despacho dinámico de acuerdo con el tipo estático a la izquierda o el tipo dinámico a la derecha;
** El rendimiento de aplicación más típico del despacho estático es la sobrecarga de métodos. ** El despacho estático ocurre durante la fase de compilación, por lo que se determina que la acción de despacho estático en realidad no la realiza la máquina virtual, por lo que algunos materiales eligen clasificarlo como "análisis" en lugar de "despacho".

El proceso de implementación del despacho dinámico está estrechamente relacionado con otra manifestación importante de la anulación del polimorfismo del lenguaje Java.

Lenguaje escrito dinámicamente

La característica clave de un lenguaje de tipo dinámico es que el proceso principal de su verificación de tipo es
"las variables no tienen tipos pero los valores variables tienen tipos" en tiempo de ejecución en lugar de en tiempo de compilación.

El siguiente es un método dinámico dentro de Java

El paquete java.lang.invoke ejecuta println () en A

Inserte la descripción de la imagen aquí

Parece una reflexión, pero
MethodHandle tiene muchas similitudes con Reflection en el uso de métodos y efectos:

Los mecanismos Reflection y MethodHandle están esencialmente simulando la invocación de métodos, pero ** Reflection está simulando la invocación de métodos en el nivel de código Java, y MethodHandle está simulando la invocación de métodos en el nivel de bytecode. ** Los tres métodos findStatic (), findVirtual (), findSpecial () en MethodHandles.Lookup deben corresponder al comportamiento de verificación de permiso de ejecución de estas instrucciones de bytecode invokestatic, invokevirtual (e invokeinterface) e invokespecial, No es necesario preocuparse por estos detalles de bajo nivel al utilizar la API de Reflection.

** El objeto java.lang.reflect.Method en Reflection es mucho más que la información contenida en el objeto java.lang.invoke.MethodHandle en el mecanismo MethodHandle. ** La primera es una imagen completa del método en el lado de Java, que incluye la firma del método, el descriptor y la representación del lado de Java de varios atributos en la tabla de atributos del método, así como información de tiempo de ejecución, como permisos de ejecución. Este último contiene solo información relevante para realizar el método. En los términos coloquiales de los desarrolladores, Reflection es un peso pesado, mientras que MethodHandle es ligero.

· Dado que MethodHandle es una simulación de la llamada de instrucción de método de bytecode, en teoría, varias optimizaciones realizadas por la máquina virtual en esta área (como la alineación de métodos) deberían estar respaldadas por una idea similar en MethodHandle (pero actualmente implementada Todavía se está mejorando), y es casi imposible implementar directamente varias medidas de optimización de puntos de llamada llamando a métodos a través de la reflexión.

Llame al método ancestro:
MethodHandles. La clase de búsqueda es similar a la adquisición de la clase insegura, esta clase no es nueva
Inserte la descripción de la imagen aquí

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

Supongo que te gusta

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