Máquina virtual JVM (3): área de memoria Java y excepción de desbordamiento de memoria

Área de datos de tiempo de ejecución

  Cuando la máquina virtual Java ejecuta el programa Java, dividirá la memoria que administra en varias áreas de datos con diferente división del trabajo.

Área de datos de tiempo de ejecución

Contador de programa

  El contador del programa es un pequeño espacio de memoria, que puede considerarse como el indicador del número de línea del código de bytes ejecutado por el hilo actual. Las operaciones básicas como la ramificación, el bucle, el salto, el manejo de excepciones y la recuperación de subprocesos deben depender de él para completarse. Para garantizar que el hilo pueda restaurarse a la posición de ejecución correcta, cada hilo necesita un contador de programa independiente todos los días. Los contadores de cada hilo no se afectan entre sí y se almacenan de forma independiente. Este tipo de área de memoria es memoria "thread-private", y no hay GC u OOM en esta área.

Pila de máquina virtual Java

  Al igual que el contador del programa, la pila de la máquina virtual Java también es privada para el subproceso, y su ciclo de vida es el mismo que el subproceso. Cuando se ejecuta cada método, la máquina virtual Java creará sincrónicamente un marco de pila para almacenar la tabla de variables locales, la pila de operandos, el enlace dinámico, la salida del método y otra información. Después de ejecutar el método, el marco de la pila se expulsa de la pila de la máquina virtual.

  La tabla de variables locales almacena varios tipos de datos básicos (booleano, byte, char, short, int, float, long, double) y referencias de objetos (tipo de referencia, que no son equivalentes al objeto en sí, pueden conocerse en tiempo de compilación. Es un puntero de referencia de la dirección inicial del objeto de ejecución, también puede apuntar a un identificador que representa el objeto u otra ubicación relacionada con el objeto) y el tipo returnAddress (apuntando a la dirección de una instrucción de bytecode). Estos tipos de datos se almacenan como ranuras de variables locales en el espacio de almacenamiento de la tabla de variables locales, donde los tipos dobles y largos ocuparán dos ranuras de variables, y los tipos de datos restantes solo ocuparán uno. No hay GC y OOM en esta área.

Pila de métodos nativos

  La función de la pila de métodos locales y la pila de máquinas virtuales es muy similar. La única diferencia es que la pila de máquinas virtuales ejecuta servicios de métodos Java para la máquina virtual, mientras que la pila de métodos locales utiliza los servicios de métodos locales para la máquina virtual.

Montón de Java

  El montón de Java es un área compartida por todos los subprocesos y se crea cuando se inicia la máquina virtual. Casi todas las instancias y matrices de objetos deben asignarse en el montón. El montón de Java compartido por todos los subprocesos se puede dividir en múltiples buffers de asignación privada de subprocesos para mejorar la eficiencia de la asignación de objetos. Se puede realizar en el tamaño de una bóveda, o se puede extender (establecido por -Xmx y -Xms). Si no hay memoria en el montón de Java para completar la asignación de energía, y el montón ya no se puede expandir, la máquina virtual de Java lanzará OOM.

Área de método

  El área de método, como el montón de Java, es un área de memoria compartida por subprocesos. Se utiliza para almacenar información de tipo, constantes, variables estáticas y datos de caché de código compilados por el compilador en tiempo real que ha cargado la máquina virtual. Antes de JDK 1.8, el área de método se colocaba en la generación permanente del montón de Java. Desde JDK1.8, el área del método se ha transferido al metaspace. Si el área de método no puede cumplir con los nuevos requisitos de asignación de memoria, se generará OOM.

Grupo constante de tiempo de ejecución

  El grupo constante de tiempo de ejecución es parte del área de método. El grupo constante después de compilar el archivo de clase se utiliza para almacenar varios literales y referencias de símbolos generados durante la compilación.Esta parte del contenido se almacenará en el grupo constante de tiempo de ejecución del área del método después de cargar la clase. El grupo constante de tiempo de ejecución tiene otra característica importante en comparación con el grupo constante de archivos de clase, que es dinámico, es decir, las constantes nuevas también se pueden colocar en el grupo constante durante el tiempo de ejecución. OOM se lanzará cuando el grupo constante ya no pueda solicitar memoria.

Exploración de objetos

Creación de objetos

  Cuando la máquina virtual Java encuentra una nueva instrucción de código de bytes, primero verificará si el parámetro de esta instrucción tiene una referencia simbólica de la clase en el grupo constante, antes de verificar si la clase representada por esta referencia simbólica se ha cargado, resuelto e inicializado. Si el proceso de carga de clase correspondiente no se realiza primero. Después de pasar la comprobación de carga de clase, asigne memoria para el objeto recién nacido. El tamaño de la memoria del objeto se puede determinar completamente después de que se completa la carga, y el tamaño correspondiente del espacio de memoria se divide en la memoria de almacenamiento dinámico.

  Suponiendo que la memoria en el almacenamiento dinámico de Java es absolutamente regular, toda la memoria utilizada se coloca en un lado, la memoria libre se coloca en el otro lado y se coloca un puntero en el medio como indicador del punto de demarcación, y luego asignar memoria es apuntar el puntero al espacio libre Mueva una distancia igual al tamaño del objeto, este método de asignación se llama "colisión de puntero".

  La memoria en el equipo de Java no es regular. La memoria usada y la libre están intercaladas entre sí. En este momento, la máquina virtual debe mantener una lista para registrar qué memoria está disponible. Al asignar, encuentre un espacio lo suficientemente grande de la lista. Asigne a objetos y actualice los registros de la lista. Este método de asignación se denomina "lista libre".

  Hay dos soluciones al problema de seguridad de subprocesos: uno es sincronizar las acciones de asignación de espacio de memoria; de hecho, la máquina virtual usa CAS con reintento fallido para garantizar la atomicidad de la operación de actualización; el otro es usar memoria La operación de asignación se realiza en diferentes espacios de acuerdo con la división de subprocesos, es decir, a cada subproceso se le asigna previamente un pequeño trozo de memoria en el almacenamiento dinámico de Java, denominado buffer de subproceso local (Buffer de asignación local de subprocesos, TLAB), que subproceso debe asignar memoria, En el que se asigna el búfer local del subproceso, solo cuando el búfer local se agota, se requiere un bloqueo de sincronización al asignar un nuevo búfer. Si la máquina virtual usa TLAB se puede configurar con el parámetro -XX: +/- UseTLAB.

Diseño de memoria de objeto

  El diseño de almacenamiento del objeto en la memoria de almacenamiento dinámico se puede dividir en tres partes: el encabezado, los datos de la instancia y el relleno.

  • Encabezado del objeto: El encabezado del objeto contiene dos partes: la primera parte se usa para almacenar los datos de tiempo de ejecución del objeto en sí, como el código hash, la edad de generación del GC, el indicador de estado de bloqueo, el bloqueo retenido por el hilo, la ID de hilo sesgada, la marca de tiempo sesgada, etc. La segunda parte es el puntero de tipo, es decir, el puntero del objeto a sus metadatos de tipo. La JVM usa este puntero para determinar qué clase del objeto es una instancia.
  • Datos de instancia: almacenan la información efectiva real del objeto, es decir, el contenido de varios tipos de campos definidos en el código del programa.
  • Relleno de alineación: sin significado especial, solo sirve como marcador de posición.

Posicionamiento de acceso a objetos

  Hay dos métodos principales de acceso para referencias de objetos: el uso de identificadores y punteros directos:

  • Si utiliza el acceso de identificador, el almacenamiento dinámico de Java puede dividir una memoria como un conjunto de identificadores.
  • Si usa el acceso directo al puntero, el diseño de la memoria del objeto en el montón de Java debe considerar cómo evitar el acceso a la información relevante de los datos de tipo. La referencia almacena la dirección del objeto directamente. Si solo accede al objeto en sí, no necesita acceder a él una vez más indirectamente. De arriba.

Supongo que te gusta

Origin www.cnblogs.com/chinda/p/12721562.html
Recomendado
Clasificación