1. Conceptos básicos
Cada programa Java se ejecuta generará un proceso Java. Cada proceso de Java puede contener uno o más hilos. Cada proceso de Java corresponde a una instancia JVM única, cada instancia de JVM corresponde a un montón, y cada hilo tiene su propia pila privada. Todas las instancias de clases (es decir, objetos) o matrices (refiriéndose a la matriz en sí, no referencias) creadas por un proceso se colocan en el montón y comparten por todos los hilos del proceso. La memoria del montón asignada en Java se inicializa automáticamente, es decir, al asignar la memoria a un objeto, se inicializarán las variables en el objeto. Aunque el espacio de almacenamiento de todos los objetos en Java se asigna en el montón, la referencia a este objeto se asigna en la pila, es decir, cuando se crea un objeto, la memoria se asigna en el montón y la pila. La memoria asignada en el montón realmente almacena el objeto creado en sí, mientras que la memoria asignada en la pila solo almacena referencias al objeto Heap. Cuando sale la nueva variable local, el espacio se asigna en el espacio de la pila y el espacio de montón. Cuando termina el ciclo de vida variable local, el espacio de la pila se recicla inmediatamente, y el área espacial del montón está esperando que GC recicle.
Concepto específico: la memoria de un JVM se puede dividir en tres áreas: montón, pila y área del método (método, también llamado área estática):
Área de pila:
1. Todos los almacenados son objetos, y cada objeto contiene información correspondiente a él (el propósito de la clase es obtener instrucciones de operación);
2.jvm tiene solo un área de montón (montón) y es compartido por todos los hilos. El montón no almacena tipos básicos y referencias de objetos, sino solo el objeto en sí y la matriz misma;
Área de pila:
1. Cada hilo contiene un área de pila, que solo guarda referencias al tipo de datos básico y objetos personalizados;
2. Los datos (tipo primitivo y referencia de objeto) en cada pila son privados y no pueden ser accedidos por otras pilas;
3. La pila se divide en 3 partes: área de variable de tipo básico, contexto de entorno de ejecución y área de instrucción de operación (instrucciones de operación de almacenamiento);
Área de método (área estática):
1. Compartido por todos los hilos. El área del método contiene todas las clases (la clase se refiere al código original de la clase. Para crear un objeto de clase, el código de la clase debe cargarse en el área del método e inicializarse) y las variables estáticas.
2. El área del método contiene elementos que siempre son únicos en todo el programa, como variables de clase y estática.
2. Demostración de ejemplo
Appmain.java
Public Class AppMain // Cuando se ejecuta, JVM coloca todo el código AppMain en el área de método {public static void main (string [] args) // El método principal en sí se coloca en el área del método. {Muestra test1 = nueva muestra ("prueba 1"); // test1 es una referencia, por lo que colocar en el área de la pila, la muestra es un objeto personalizado, que debe colocarse en el montón. Muestra test2 = nueva muestra ("prueba 2"); test1.printname (); test2.printname (); }} muestra de clase pública // Al ejecutar, JVM pone toda la información de AppMain en el área de método { /** Nombre de ejemplo* /Nombre de cadena privada; // Después de una nueva instancia de muestra, la referencia de nombre se coloca en el área de la pila, el nombre del objeto de cadena correspondiente se coloca en el constructor Heap/***/public suestra (nombre de cadena) {this .name = name; } /** salida* /public void printname () // Cuando no hay objeto, el método de impresión se coloca en el área del método junto con la clase de muestra. {System.out.println (nombre); }}Al ejecutar el programa, primero inicie un proceso de máquina virtual Java. Este proceso primero encuentra el archivo AppMain.Class de ClassPath, lee los datos binarios en el archivo y luego almacena la información de clase de la clase AppMain en el área de método del área de datos de tiempo de ejecución. Este es el proceso de carga de la clase AppMain.
A continuación, la máquina virtual Java localiza el código bytecodo del método Main () de la clase AppMain en el área del método y comienza a ejecutar sus instrucciones. La primera declaración de este método main () es:
La copia del código es la siguiente:
Muestra test1 = nueva muestra ("test1");
El proceso de ejecución de esta declaración:
1. La máquina virtual Java encontró la información de tipo de la clase de muestra en el área del método, pero no se encontró, porque la clase de muestra no se ha cargado en el área del método (se puede ver aquí que las clases internas en Java existen por separado, y al principio no se cargará con la clase contenida, y no se cargará hasta que se use). La máquina virtual Java carga inmediatamente la clase de muestra y almacena la información de tipo de clase de muestra en el área de método.
2. La máquina virtual Java primero asigna memoria para una nueva instancia de muestra en el área de almacenamiento de almacenamiento, y almacena una dirección de memoria en el área de método donde la información de tipo de clase de muestra se almacena en la memoria de la instancia de muestra.
3. En el proceso JVM, cada hilo tendrá una pila de llamadas de método, que se utiliza para rastrear una serie de procesos de llamadas de método durante la ejecución del hilo. Cada elemento en la pila se llama marco de pila. Cada vez que un subproceso llama a un método, se empujará un nuevo marco a la pila de métodos. Los cuadros aquí se utilizan para almacenar los parámetros del método, las variables locales y los datos temporales durante la operación.
4. Test1 antes de "=" es una variable (una referencia a un objeto de muestra) definida en el método main (), por lo que se agregará a la pila de llamadas del método Java del hilo principal que ejecuta el método main (). Y "=" apuntará esta variable Test1 a la instancia de muestra en el área de Heap.
5. El JVM continúa creando otra instancia de muestra en el área de almacenamiento de almacenamiento, y agrega una variable Test2 a la pila de llamadas del método del método principal, que apunta a la nueva instancia de muestra que se acaba de crear en el área de Heap.
6. El JVM ejecuta su método printname () a su vez. Cuando la máquina virtual Java ejecuta el método test1.printname (), la máquina virtual Java localiza la instancia de muestra en el área de Heap en base a la referencia de la variable local test1, y luego localiza la información de tipo de clase de muestra en el método basado en el referencia de muestra, obtiene el método de inicio de la impresión de la impresión.
Iii. Distinguir
La diferencia entre el montón y la pila en el idioma Java:
1. Stack y Heap son ambos lugares utilizados por Java para almacenar datos en la RAM. A diferencia de C ++, Java administra automáticamente pilas y montones, y los programadores no pueden configurar pilas o montones directamente.
2. La ventaja de la pila es que la velocidad de acceso es más rápida que el montón, solo solo de los registros ubicados directamente en la CPU. Pero la desventaja es que el tamaño de los datos y la vida útil en la pila deben ser deterministas y carecer de flexibilidad. Además, se pueden compartir datos de pila (consulte la introducción a continuación para más detalles). La ventaja del montón es que puede asignar dinámicamente el tamaño de la memoria, y la vida útil no tiene que ser contada al compilador de antemano. El recolector de basura de Java recopilará automáticamente los datos que ya no se usan. Pero la desventaja es que la memoria debe asignarse dinámicamente en tiempo de ejecución, la velocidad de acceso es más lenta.
2 tipos de datos en Java:
Uno son los tipos primitivos, con 8 categorías, a saber, int, corto, largo, byte, flotante, doble, booleano, char (tenga en cuenta que no hay un tipo básico de cadena). Este tipo de definición se define mediante una forma como int a = 3; largo B = 255L; y se llama variable automática. Las variables automáticas tienen valores literales, no instancias de clases, es decir, no son referencias a clases, y no hay clase aquí. Por ejemplo, int a = 3; Aquí A es una referencia que apunta al tipo INT, que apunta al valor literal de 3. Debido al tamaño y la vida útil de estos datos literales, estos valores litentes se definen fijamente en un bloque de programa, y el valor del campo desaparece después de que sale el bloque del programa), y existe en la pila de velocidad.
La pila tiene una característica muy importante: los datos que existe en la pila se pueden compartir. Supongamos que definimos al mismo tiempo: int a = 3; int b = 3; El compilador primero procesa int a = 3; Primero, creará una referencia con una variable A en la pila, y luego averigüe si hay una dirección con un valor literal de 3. Si no se encuentra, abrirá una dirección con el valor literal de 3, y luego señale A a la dirección de 3. Luego procese int b = 3; Después de crear la variable de referencia de B, ya que ya hay un valor literal de 3 en la pila, B se apunta directamente a la dirección de 3. De esta manera, A y B apuntan a 3 al mismo tiempo.
Esta referencia a los valores literales es diferente de la de los objetos de clase. Suponiendo que las referencias de dos objetos de clase apunten a un objeto al mismo tiempo, si una variable de referencia del objeto cambia el estado interno del objeto, la otra variable de referencia del objeto refleja inmediatamente este cambio. En cambio, modificar su valor a través de una referencia literal no hará que otro valor se cambie en consecuencia. Como en el ejemplo anterior, después de definir los valores de A y B, deje a = 4; Entonces, B no será igual a 4, o igual a 3. Dentro del compilador, cuando se encuentre a = 4, volverá a buscar si hay un valor literal de 4 en la pila. Si no, vuelva a abrir la dirección para almacenar el valor de 4; Si ya existe, apunte directamente a esta dirección. Por lo tanto, el cambio en el valor A no afectará el valor b.
Otro tipo son los datos de la clase de empaque, como entero, cadena, doble, etc. que envuelve los tipos de datos básicos correspondientes. Todos estos datos de clase existen en el montón. Java usa la instrucción nueva () para mostrar el compilador y solo crea dinámicamente según sea necesario en el tiempo de ejecución, por lo que es más flexible, pero la desventaja es que toma más tiempo.
4. Resumen
La estructura de asignación de memoria Java sigue siendo muy clara. Si desea comprenderlo a fondo, puede consultar los libros relacionados con JVM. En Java, lo más problemático de la asignación de memoria es el objeto de cadena. Debido a su naturaleza especial, muchos programadores son propensos a la confusión. Lo explicaré en detalle en el próximo artículo.