Jvmmemorymodel
Este artículo presenta principalmente el área de datos de tiempo de ejecución (RuntimeDataAreas) descrito en la especificación JVM. Estas áreas están diseñadas para almacenar datos utilizados por el propio JVM o programas que se ejecutan en el JVM.
Primero descripción de la JVM, luego introduzcamos el Bytecode y finalmente introduzcas diferentes áreas de datos.
Descripción general
Como abstracción del sistema operativo, JVM asegura que el mismo código se comporte de manera consistente en diferentes sistemas de hardware u operaciones.
Por ejemplo:
Para el tipo básico int, es un entero firmado de 32 bits, independientemente del sistema operativo de 16 bits/32 bits/64 bits. Rango de -2^31 a 2^31-1
Independientemente de si el sistema operativo o el hardware es un orden de byte grande o pequeño, se asegura que los datos en la memoria almacenados y utilizados por el JVM son un orden de bytes grande o pequeño (lea primero el byte de alta bits)
Las diferentes implementaciones de JVM pueden diferir un poco, pero generalmente son las mismas.
La imagen de arriba es una descripción general de un JVM
El JVM interpreta el Bytecode generado por el compilador. Aunque JVM es la abreviatura de las máquinas virtuales de Java, siempre que sea un lenguaje que se pueda compilar en Bytecode, se puede ejecutar en función del JVM, como Scala, Groovy <� "/Kf/Ware/VC/" TITA = "_ en blanco"> VCD4NCJXWPS6QWCUX3MPIXRW3SBXETMXFZEKVT6OS19A92SLRU+GXU2NSYXNZBG9HZGVYVNPU2LKIU7Q05R W91MVQ0MQXYV2+3CF41TC1XNK7UPBH+NPYO6ZWQRXAVNPU2MV8TCRJBGFZC2XVYWRLCRG7Z/Q72BVY1D9KVK3NO9A51MVQ0KGJPCCC 9WPG0KPHA+VNPU2LXE19A92SLRZAI5/DA00NDS/CFMKGV4ZWN1DGLVBIBLBMDPBMUPVFJQ0L3IYS26ZDA00NA8L3A+DQO8CD7WT NDQ0V3H5TDO0QQ05RSIS8ZQ8SNPZ8LOXKOSSCJI57PM0PLWTNDQTB3EXNK70NCJRLVY1D/K/B7DVMBL47XE1TC85L3HUFS8L3A+D Qo8cd7wtndq0v3h5tkyulru8lsmwo3t67xxsuoy2df3z7xns7xevbu7ptwvcd4ncjxwpioquty24epwtba8yrxp1shlvltksbhg 0uu5pstckepjvd1qdxn0igluihrpbwupoanksvs+zcrhsng+rboj1rtq0lxetprc6yjiylxjtprc6ymx4nlrs8mxvrxytprc6yho YXRPDMUGQ29KZSMHO7TMT8VKSVSX4NLRYFQZYBT6WUU1XMF40/KZXS6QPC9WPG0KPHA+TPRC67U6TOBH+CHDB2RLIENH Y2GPOAO8TMQXSEDS67Y8YVUOSKLUKBY2TPO1XMZHUN/BY0PWTBXE0NTE3COQPC9WPG0KPGGYIGLKPQ == "Basado en la pila Arquitectura "> Arquitectura basada en pila
JVM utiliza una arquitectura basada en pila. Aunque la pila es transparente para los desarrolladores, tiene un papel o influencia muy importante en el bytecode y JVM generados.
Los programas que desarrollamos convertirán operaciones de bajo nivel y las almacenarán en Bytecode. Mapa de instrucciones de operación a través de operandos en el JVM. Según la especificación JVM, los parámetros requeridos por las instrucciones de operación se obtienen de la pila de operando.
Demos un ejemplo de agregar dos números. Esta operación se llama IADD. El siguiente es el proceso de 3+4 en bytecode
Primero empuje 3 y 4 en la pila de operando
Llame a la Directiva IADD
La instrucción IADD aumenta 2 números desde la parte superior de la pila de operando
El resultado de 3+4 se empuja a la pila de operando para su uso posterior
Este enfoque se llama arquitectura basada en pila. Hay otras formas de manejar operaciones de bajo nivel, como la arquitectura basada en registros.
Bytecode
Java Bytecode es el resultado de convertir el código fuente de Java en una serie de operaciones de bajo nivel. Cada operación consiste en un código de operación u código de operación con cero o más parámetros de longitud de bytes (pero la mayoría de las operaciones usan parámetros obtenidos a través de la pila de operando). Un byte puede representar 256 números, de 0x00 a 0xff, y actualmente a Java8, se utilizan un total de 204.
Los siguientes enumera diferentes tipos de códigos de op con código de byto, así como su rango y descripción simple
Constantes: empuje el valor del grupo constante o un valor conocido en la pila de operando. 0x00 - 0x14
Cargas: presione los valores de la variable local en la pila de operando. 0x15 - 0x35
Tiendas: Valor de carga desde la pila de operando a la variable local 0x36 - 0x56
Pila: Pila de operando de proceso 0x57 - 0x5f
Matemáticas: Obtenga valor de la pila de operando para el cálculo matemático básico 0x60 - 0x84
Conversiones: Convierta entre los tipos 0x85 - 0x 93
Comaprisons: operación de comparación de dos valores 0x94 - 0xa6
Controles: Ejecutar GOTO, retorno, bucle, etc. Operaciones de control 0xa7 - 0xb1
Referencias: ejecuta objetos o matrices de asignación, y obtiene o verifica las referencias a objetos, métodos y métodos estáticos. También se pueden llamar métodos estáticos. 0xb2 - OXC3
Extendido: extendido: operaciones de las otras categorías que se agregaron después. Desde el valor 0xc4 a 0xc9
(¿Qué significa esta oración? ... ... ... ... ... ... ... ... ... ... ... ... ... ...
Reservado: la implementación JVM utiliza ranuras 0xCA, Oxfe, Oxff
Estas 204 operaciones son muy simples, dan algunos ejemplos
IFEQ (0x99) determina si los dos valores son iguales
IADD (0x60) agrega dos números
I2L (0x85) convierte un bit de intento largo
ArrayLength (0xbe) Devuelve la longitud de la matriz
Pop (0x57) Pop un valor desde la parte superior de la pila de operando
Necesitamos un compilador para crear archivos Bytecode, y el compilador Java estándar es Javac en JDK.
prueba de clase pública {public static void main (string [] args) {int a = 1; int b = 15; int resultado = add (a, b); } public static int add (int a, int b) {int resultado = a + b; resultado de retorno; }}Puede obtener el archivo bytecode de "test.class" a través de "javac test.java". Los archivos de Bytecode son binarios, podemos convertir archivos binarios de bytecode en formulario de texto a través de Javap
Java -verbosa prueba. Clase
Classfile /c:/tmp/test.class Último modificado 1 avr. 2015; Tamaño 367 bytes MD5 CHECKSUM ADB9FF75F12FC6CE1CDDE22A9C4C7426 Compilado a partir de "Test.Java" Class Public Com.CodingGeek.jvm.Test SourceFile: "Test.Java" Versión menor: 0 Versión principal: 51 Flags: Acc_Public, Acc_SuperConStant Pool: #1 = Methode java/lang/object. "<Init>" :() v #2 = Methodref #3. #16 // com/codinggeek/jvm/test.add: (ii) i #3 = class #17 // com/codinggeek/jvm/test #4 = class #18 // java/lang/objeto #5 = utf8 <> #6 = util Linenumberable #9 = UTF8 Main #10 = UTF8 ([ljava/lang/string;) v #11 = utf8 add #12 = utf8 (ii) i #13 = UTF8 SourceFile #14 = UTF8 test.Java #15 = NameAndtype #5: #6 // "<Init>": V #16 = NAMEANDPE #11: #17 = UTF8 com/codinggeek/jvm/test #18 = utf8 java/lang/object {public com.codinggeek.jvm.test (); FLAGS: ACC_Public Code: stack = 1, locals = 1, args_size = 1 0: aload_0 1: invokespecial #1 // método java/lang/object. "<Init>" :() v 4: return LinenUnumeTable: línea 3: 0 public static void main (java.lang.string []); FLAGS: ACC_Public, Código ACC_STAtic: stack = 2, locals = 4, args_size = 1 0: iconst_1 1: istore_1 2: bipush 15 4: istore_2 5: iload_1 6: iload_2 7: Invokestatatic #2 // método agregar: (ii) i 10: istore_3 11: retorno lineal 5 Línea 9: 11 Public static int add (int, int); FLAGS: ACC_Public, ACC_STAtic Code: stack = 2, locals = 3, args_size = 2 0: iload_0 1: iload_1 2: iadd 3: istore_2 4: iload_2 5: Ireturn Linenumbable: Línea 12: 0 Línea 13: 4}Se puede ver que Bytecode no es solo una traducción simple del código Java, incluye:
Una descripción constante del grupo de la clase. Las piscinas constantes son áreas de datos JVM utilizadas para almacenar metadatos de clase, como nombres de métodos, listas de parámetros, etc. dentro de la clase. Cuando el JVM carga una clase, los metadatos se cargarán en la piscina constante
Proporcione la información de posición específica de las funciones y las variables TMALL en Bytecode a través de la tabla de números de fila y la tabla de variables locales.
Traducción del código Java (incluidas las construcciones ocultas de la clase principal)
Proporciona operaciones más específicas en pilas de operandos y formas más completas de pasar y obtener parámetros
A continuación se muestra una descripción simple de la información de almacenamiento de archivos bytecode
Classfile {U4 Magic; U2 minor_version; U2 major_version; U2 constant_pool_count; cp_info constant_pool [constant_pool_count-1]; U2 access_flags; U2 this_class; U2 super_class; U2 interfaces_count; interfaces u2 [interfaces_count]; U2 Fields_Count; Field_info Fields [Fields_Count]; ATRIBUTOS U2_COUNT; attribute_info Atributes [Attributes_Count];}Área de datos de tiempo de ejecución
El área de datos de tiempo de ejecución es el área de memoria diseñada para almacenar datos. Estos datos son para usar por desarrolladores o JVM internamente.
Montón
El montón se crea cuando se inicia el JVM y es compartido por todos los hilos JVM. Todas las instancias y matrices de clase se asignan al montón (creado por nuevo).
El montón debe ser administrado por un recolector de basura, que es responsable de liberar objetos creados por el desarrollador y no se volverá a utilizar.
En cuanto a la estrategia de recolección de basura, está determinada por la implementación JVM (por ejemplo, HotSpot proporciona múltiples algoritmos).
Existe un límite máximo para la memoria de montón. Si se excede este valor, el JVM lanzará una excepción OutOfMemroy.
Área de método
El área del método también es compartida por todos los hilos del JVM. Lo mismo se crea con JVM Startup. Los datos almacenados en el área del método están cargados desde el código de bytecodo por el cargador de clases, que existirá de manera consistente durante la ejecución de la aplicación, a menos que el cargador de clases que los cargue se destruya o se detenga el JVM.
El área del método almacena los siguientes datos:
Información de clase (nombre del atributo, nombre del método, nombre de clase principal, nombre de excusa, versión, etc.)
Métodos y bytecodos construidos
Piscina constante de tiempo de ejecución creado al cargar cada clase
La especificación JVM no obliga a las áreas del método que se implementarán en el montón. Antes de JAVA7, las zonas de método implementadas en HotSpot utilizan una región llamada Permgen. La banda permanente está adyacente al montón (la gestión de la memoria es la misma que el montón), el bit predeterminado es de 64 MB
A partir de Java8, HPTSpot utiliza una memoria local separada para implementar el área del método y nombrar el área de metadatos (MetaSpace). El espacio máximo disponible en el área de metadatos es la memoria disponible de todo el sistema.
Si el método no puede solicitar la memoria disponible, el JVM también se lanzará OutOfMemoryError.
Piscina constante de tiempo de ejecución
La piscina constante de tiempo de ejecución es parte del área del método. Debido a la importancia de ejecutar una piscina constante a los metadatos, se describe por separado en la especificación de Java fuera del área del método. La piscina constante de tiempo de ejecución crece con las clases e interfaces cargadas.
Las piscinas constantes son una tabla de sintaxis en los idiomas tradicionales. En otras palabras, cuando se llama a una clase, método o propiedad, el JVM busca la dirección real de estos datos en la memoria a través del grupo constante de tiempo de ejecución. La piscina constante de tiempo de ejecución también contiene constantes de literales de cadena o tipos primitivos
Agitar myString = "Esta es una cadena litera" estática final int my_constant = 2;
PC (contador del programa) Registro (por hilo) El registro de PC (por hilo)
Cada hilo tiene su propio registro de PC (contador de programas), que se crea junto con la creación de hilos. Cada hilo solo puede ejecutar un método en un momento en el tiempo, llamado método actual del hilo. El registro de PC contiene la dirección del JVM que actualmente ejecuta la instrucción (en el área de método).
Si el método ejecutado actualmente es un método local, el valor del registro de PC está indefinido
Pila de máquina virtual por hilo-java-virtual-máquina-machine-stacks-per-horthing "> pila de máquinas virtuales (por hilo) pilas de máquina virtual Java (por hilo)
La pila de máquinas virtuales almacena múltiples marcos, por lo que antes de describir la pila, echemos un vistazo a los marcos primero.
Marcos
Una trama es una estructura de datos que contiene múltiples datos que representan el estado del método actual que el subproceso está ejecutando:
Pila de operando: como se mencionó anteriormente, las instrucciones de Bytecode usan la pila de operandos para pasar los parámetros
Matriz de variables locales: esta matriz contiene todas las variables locales dentro de un alcance del método ejecutado actualmente. Esta matriz puede contener un tipo primitivo, una referencia o una dirección de retorno. El tamaño de la matriz de variables locales se determina en el tiempo de compilación. JVM usa variables locales para pasar los parámetros al llamar al método, y la matriz de variables locales del método llamado se crea a través de la pila de operando del método de llamada.
Referencia de grupo constante de tiempo de ejecución: Referencias al grupo constante del método actual de la clase actual. El JVM utiliza referencias de grupo constante para pasar señales a referencias de memoria real.
Pila (pila)
Cada hilo de JVM tiene una pila JVM privada, que se crea al mismo tiempo que el hilo. Java Virtual Machine Stack almacenan marcos. Cada vez que se llama un método, se crea y empuja un marco a la pila de máquinas virtuales. Cuando se ejecuta este método, el marco también se destruirá (independientemente de si el método se ejecuta normalmente o si se lanza una excepción)
Solo hay un cuadro disponible durante la ejecución de un hilo. Este marco se llama marco actual.
Las operaciones en variables locales y pilas de operandas generalmente se acompañan de referencias al marco actual.
Veamos otro ejemplo de adición
public int add (int a, int b) {return a + b;} public void functionA () {// algún código sin función llame int result = add (2,3); // Llamar a la función b // algún código sin llamada de función}Método interno A, el marco A es el marco actual, ubicado en la parte superior de la pila de máquina virtual. Al comienzo de llamar al método ADD, se crea un nuevo cuadro B y se empuja a la pila de máquinas virtuales. El cuadro B se convierte en el nuevo marco actual.
La matriz de variable local del marco B se llena con datos en la pila de operando de la trama A. Cuando finaliza el método Agregar, el cuadro B se destruye y el cuadro A se restablece como el marco actual. El resultado del método ADD se empuja a la pila de operando del marco A, de modo que el método A puede obtener el resultado de ADD a través de la pila de operandos del marco A.
Resumir
Lo anterior se trata del análisis del área de datos del tiempo de ejecución de la máquina virtual Java. Espero que sea útil para todos.
Si hay alguna deficiencia, deje un mensaje para señalarlo.