[Java] Aprendizaje JVM (4)

asignación de objetos

Proceso de creación de objetos en JVM

inserte la descripción de la imagen aquí

asignación de memoria de objetos

Cuando la máquina virtual encuentra una nueva instrucción, primero verifica si está cargada por el cargador de clases, si no, primero debe ejecutar el proceso de carga de clases correspondiente.

La carga de clases es el proceso de cargar una clase en el área de datos de tiempo de ejecución de la JVM.

1)检查加载

Primero verifique si el parámetro de esta instrucción puede ubicar una referencia simbólica de una clase en el conjunto de constantes (referencia simbólica: una referencia simbólica describe el objetivo al que se hace referencia con un conjunto de símbolos), y verifique si la clase ha sido cargada, analizada e inicializada .

符号引用 : Una referencia simbólica describe el objetivo al que se hace referencia como un conjunto de símbolos. Las referencias de símbolos pueden ser cualquier forma de literales. Cuando se compila JAVA, cada clase de Java se compilará en un archivo de clase, pero la máquina virtual no conoce la dirección (dirección real) de la clase a la que se hace referencia al compilar, así que use referencias de símbolos en su lugar. , y en la fase de análisis de clases (la subsiguiente carga de clases de JVM se mencionará en detalle) es convertir esta referencia de símbolo en una etapa de dirección real.

Cuando una clase Java (que se supone que es la clase People) se compila en un archivo de clase, si la clase People hace referencia a la clase Tool, pero la clase People no conoce la dirección de memoria real de la clase a la que se hace referencia durante la compilación, por lo que solo es simbólica referencias (org. simple.Tool) en su lugar. Cuando el cargador de clases carga la clase People, la dirección de memoria real de la clase Tool se puede obtener a través de la máquina virtual en este momento, por lo que el símbolo org.simple.Tool se puede reemplazar con la dirección de memoria real de la clase Tool.

2)分配内存

La máquina virtual luego asignará memoria para el objeto recién nacido. La tarea de asignar espacio para un objeto es equivalente a dividir un cierto tamaño de memoria del montón de Java.

指针碰撞
Si la memoria en el montón 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, entonces la memoria asignada es solo para poner ese puntero Mueva una distancia igual al tamaño del objeto al espacio libre, este método de asignación se llama "colisión de puntero".

inserte la descripción de la imagen aquí
空闲列表
Si la memoria en el montón de Java no es regular, y la memoria usada y la memoria libre están intercaladas, entonces no hay manera de simplemente colisionar punteros.La máquina virtual debe mantener una lista para registrar qué bloques de memoria están disponibles. un espacio lo suficientemente grande de la lista para asignar a la instancia del objeto y actualizar los registros en la lista.Este método de asignación se denomina "lista libre".
inserte la descripción de la imagen aquí
El método de asignación a elegir está determinado por si el almacenamiento dinámico de Java es regular, y si el almacenamiento dinámico de Java es regular está determinado por si el recolector de elementos no utilizados tiene una función de compactación.

Si se trata de un recolector de basura con terminación comprimida como Serial y ParNew, el sistema utiliza colisión de punteros, lo cual es simple y eficiente.

Si usa un recolector de basura sin compresión (organización) como CMS, en teoría solo puede usar una lista libre más compleja.

并发安全
Además de cómo dividir el espacio disponible, hay otra cuestión que debe tenerse en cuenta. La creación de objetos es un comportamiento muy frecuente en la máquina virtual. Aunque solo se modifique la ubicación a la que apunta un puntero, no es seguro para subprocesos. en condiciones concurrentes, puede suceder que se esté asignando memoria al objeto A, el puntero no ha tenido tiempo de modificarse y el objeto B usa el puntero original para asignar memoria al mismo tiempo.

CAS机制
Hay dos soluciones a este problema: una es sincronizar la acción de asignar espacio de memoria; de hecho, la máquina virtual usa CAS con reintentos fallidos para garantizar la atomicidad de las operaciones de actualización;

inserte la descripción de la imagen aquí

CAS(Compare And Swap)Es un mecanismo utilizado en la programación concurrente para implementar algoritmos sin bloqueo. En la JVM, CAS es una operación atómica que se utiliza para garantizar la coherencia cuando varios subprocesos leen, comparan y actualizan simultáneamente una variable compartida.

La operación CAS consta de tres pasos: comparar el valor actual, actualizar si es igual, de lo contrario, volver a intentarlo. Este proceso es atómico y no puede ser interrumpido por la interferencia de otros subprocesos. Las operaciones CAS generalmente usan operaciones atómicas en variables compartidas en un entorno concurrente, como la actualización de contadores y banderas.

En la JVM, las operaciones CAS se implementan con el soporte del hardware subyacente. Utiliza instrucciones atómicas proporcionadas por el procesador (como instrucciones de comparación e intercambio), que pueden implementar operaciones atómicas de lectura, comparación y actualización en el nivel específico de instrucción de la CPU. Cuando varios subprocesos realizan operaciones CAS al mismo tiempo, solo un subproceso puede realizar con éxito la operación de actualización y otros subprocesos deben volver a intentarlo o adoptar otras estrategias.

La ventaja de CAS es que evita la sobrecarga del uso de bloqueos, mejora el rendimiento de la concurrencia y no tiene riesgo de interbloqueo. Sin embargo, CAS también tiene algunos problemas. Dado que las operaciones CAS se comparan en función del valor actual, en situaciones de alta simultaneidad, si varios subprocesos realizan operaciones CAS al mismo tiempo y compiten por la misma variable compartida, puede provocar una gran cantidad de reintentos y giros, lo que reduce la eficiencia.

Para resolver el problema ABA de la operación CAS (es decir, en el proceso de comparación de valores, las variables compartidas pueden ser modificadas al mismo valor por otros subprocesos, lo que resulta en un error de juicio), JVM proporciona clases atómicas bajo java.util.concurrent. paquete atómico, como AtomicInteger, AtomicLong, etc., proporcionan la encapsulación de operaciones CAS, que pueden realizar operaciones atómicas de manera más conveniente.

分配缓冲

La otra es dividir la asignación de memoria en diferentes espacios según los hilos, es decir, cada hilo asigna previamente una pequeña parte de la memoria privada en el montón de Java, es decir, el búfer de asignación de hilo local (Thread Local Allocation Buffer, TLAB ), cuando se inicializa el subproceso, la JVM también solicitará una parte de la memoria de un tamaño específico, que solo utiliza el subproceso actual, de modo que cada subproceso tenga un búfer independiente. Si es necesario asignar memoria, es asignado en su propio Buffer, de modo que no haya En el caso de competencia, la eficiencia de asignación puede mejorarse en gran medida. Cuando la capacidad del buffer no sea suficiente, solicite un bloque del área Eden nuevamente y continúe usándolo.

El propósito de TLAB es permitir que cada subproceso de aplicación Java use su propio puntero de asignación dedicado para asignar espacio al asignar espacio de memoria para nuevos objetos, lo que reduce la sobrecarga de sincronización.

TLAB solo permite que cada subproceso tenga un puntero de asignación privado, pero el espacio de memoria subyacente para almacenar objetos sigue siendo accesible para todos los subprocesos, pero otros subprocesos no pueden asignarse en esta área. Cuando una TLAB está llena (la parte superior del puntero de asignación toca el límite de asignación), se solicita una nueva TLAB.

3)内存空间初始化

(Tenga en cuenta que no es un método de construcción) Una vez completada la asignación de memoria, la máquina virtual debe inicializar el espacio de memoria asignado a valores cero (como el valor int es 0, el valor booleano es falso, etc.) . Este paso asegura que los campos de instancia del objeto se puedan usar directamente en el código Java sin asignar valores iniciales, y el programa puede acceder a los valores cero correspondientes a los tipos de datos de estos campos.

4)设置

A continuación, la máquina virtual debe realizar los ajustes necesarios para el objeto, como de qué clase es una instancia, cómo encontrar la información de metadatos de la clase (las clases de Java se representan como metadatos de clase dentro de la máquina virtual de punto de acceso de Java) y el código hash del objeto, la edad generacional de GC del objeto y otra información. Esta información se almacena en el encabezado de objeto del objeto.

5)对象初始化

Después de completar el trabajo anterior, desde la perspectiva de la máquina virtual, se ha generado un nuevo objeto, pero desde la perspectiva del programa Java, la creación del objeto acaba de comenzar y todos los campos siguen siendo cero. Por lo tanto, en términos generales, después de ejecutar la nueva instrucción, el objeto se inicializará (construirá) de acuerdo con los deseos del programador, de modo que se pueda generar completamente un objeto realmente utilizable.

Disposición de la memoria del objeto

inserte la descripción de la imagen aquí

En la máquina virtual HotSpot, el diseño de los objetos almacenados en la memoria se puede dividir en tres áreas: encabezado de objeto (Header), datos de instancia (Instance Data) y relleno de alineación (Padding).

El encabezado del objeto incluye dos partes de información. La primera parte se utiliza para almacenar los datos de tiempo de ejecución del propio objeto, como el código hash (HashCode), la edad de generación del GC, el indicador de estado de bloqueo, el bloqueo retenido por el subproceso, la ID del subproceso sesgado, marca de tiempo sesgada, etc.

La otra parte del encabezado del objeto es el puntero de tipo, que es el puntero del objeto a sus metadatos de clase.La máquina virtual usa este puntero para determinar de qué clase es una instancia el objeto.

Si el objeto es una matriz java, entonces hay otro dato que se usa para registrar la longitud de la matriz en el encabezado del objeto.

La tercera parte del relleno de alineación no existe necesariamente y no tiene un significado especial, solo actúa como marcador de posición. Porque el sistema de administración de memoria automática de HotSpot VM requiere que el tamaño del objeto sea un múltiplo entero de 8 bytes. Cuando otras partes de datos del objeto no están alineadas, debe completarse con el relleno de alineación.

对象的访问定位
El propósito de crear un objeto es usar el objeto Nuestro programa Java necesita manipular el objeto específico en el montón a través de los datos de referencia en la pila. En la actualidad, existen dos métodos de acceso principales, que utilizan identificadores y punteros directos.

句柄
Si usa un identificador para acceder, se asignará una parte de la memoria en el montón de Java como un grupo de identificadores. La referencia almacena la dirección del identificador del objeto, y el identificador contiene la información de dirección específica de los datos y el tipo de la instancia del objeto. datos.

La mayor ventaja de usar un identificador para acceder es que la referencia almacena una dirección de identificador estable. Cuando se mueve el objeto (mover objetos durante la recolección de basura es un comportamiento muy común), solo se cambiará el puntero de datos de la instancia en el identificador, y la referencia en sí no necesita Revisar.

直接指针
Si usa un puntero directo para acceder, lo que se almacena en la referencia es directamente la dirección del objeto.

Estos dos métodos de acceso a objetos tienen sus propias ventajas. La mayor ventaja de utilizar el acceso de puntero directo es que es más rápido, lo que ahorra el costo de tiempo del posicionamiento del puntero. Dado que el acceso a objetos es muy frecuente en Java, este tipo de sobrecarga se acumula. Mucho más tarde es también un costo de implementación muy considerable.

Para Sun HotSpot, utiliza acceso de puntero directo para el acceso a objetos.

Supongo que te gusta

Origin blog.csdn.net/qq_43358469/article/details/131391502
Recomendado
Clasificación