Modelo de memoria Java y estructura de memoria JVM

1. Modelo de memoria JVM

1. Estructura de memoria JVM y JVM

(1) composición de JVM

inserte la descripción de la imagen aquí

(2) flujo de ejecución del programa Java

Flujo de ejecución del programa Java: el compilador javac.exe compila el archivo fuente de Java en un archivo .class (archivo JVM) y luego lo ejecuta java.exe. La JVM puede ser multiplataforma y no estar completamente restringida por el rendimiento del hardware.

(3) Cargador de clases y mecanismo de carga principal

① Cargador de clases: La función es cargar desde cualquier posición.
Hay tres capas de carga:
la primera capa es bootstrap, que carga funciones del sistema, que JDK no puede obtener, como str.getClass().getClassLoader()=null de la clase String; la segunda capa es el cargador de plataforma
( JDK1.9) /cargador de clases extendidas (extClassLoader) (JDK1.8);
la tercera capa es un cargador de aplicaciones de clase personalizada, como user.getClass().getClassLoader() de la clase User para obtener XXXAppClassLoader@XXX, en la parte superior de it.getParent () puede obtener el segundo cargador.

②Mecanismo de carga principal: primero delegue la tarea de carga a la clase principal y recurra a su vez. El cargador del sistema se encarga de las clases del sistema y otros cargadores de clases se encargan de las clases personalizadas. Puede evitar la carga repetida de clases del sistema y evitar que se manipule la biblioteca API.

(4) estructura de memoria JVM (área de datos de tiempo de ejecución de Java)

①Área de método: el área de memoria más importante, compartida por varios subprocesos, guarda información de clase (nombre/miembro/interfaz/clase principal), el mecanismo de reflexión es una parte importante e implementa dinámicamente operaciones de clase.
② Memoria de pila (Heap): guarda la información real del objeto, y esta memoria implica el problema de liberación (GC).
③Memoria de pila (Pila): el espacio privado del hilo, habrá un marco de pila en cada llamada de método, y se adopta el principio de diseño de primero en entrar, último en salir.
Cuando el espacio de memoria es constante, cuanto mayor sea la pila, menor será el número de subprocesos. No se requiere GC y la eficiencia es mayor que la del montón.
(1) Tabla de variables locales: almacena parámetros locales o parámetros formales, lo que permite reservar ranuras de 32 bits (solt), si la longitud supera los 32 bits, debe abrir dos ranuras consecutivas (larga, doble) (2) Pila de
operandos : Realiza todas las operaciones de cálculo del método. Primero en llegar último en irse.
(3) Referencia de grupo constante: instancia de clase String/Integer
(4) Salida del método: el punto donde se reanuda la ejecución después de ejecutar el método
(5) Enlace dinámico: si la interfaz llama a su método implementado a través de él,
los más importantes son los tabla de variables locales y operación Pila de números: como a=1, b=2, c = (a+b)*4. ① coloque 1 en la parte inferior de la pila de operandos primero, ② luego guárdelo en la tabla de variables locales, lo mismo se aplica para 2, donde la tabla de variables locales también registra el orden (por ejemplo, 1 es el primer valor int), y luego poner 1 y 2 se lleva a la pila, luego se calcula en la CPU, y luego 3 se vuelve a poner en la pila, y 3 y 4 en el grupo constante se sacan para calcularse en la CPU, luego se vuelven a poner la pila, y luego 12 se coloca en la tabla de variables locales.
④Contador de programa: la codificación secuencial de las instrucciones de ejecución, como ① y ② en el ejemplo anterior, la proporción es casi insignificante.
⑤Pila de métodos nativos: similar a la memoria de pila, la diferencia es que solo sirve métodos locales (modificación nativa).

Nota: El área de métodos y el montón en el área de datos de tiempo de ejecución son compartidos por subprocesos, y la pila de la máquina virtual, la pila de métodos locales y el contador del programa están aislados por subprocesos, y cada subproceso tiene su propia pila.

(5) Diagnóstico y optimización de desbordamiento de memoria

①Error de desbordamiento de pila (StackOverflowError)
a. Demasiados marcos de pila: si la llamada recursiva no establece la condición de finalización correctamente
b. Marco de pila demasiado grande: conversión de datos json, objeto objeto anidado

Error común 1: java.lang.OutOfMemoryError: no se puede crear un nuevo subproceso nativo
Motivo del error: el espacio de la pila no es suficiente para crear subprocesos adicionales, se crean demasiados subprocesos o el espacio de la pila es muy pequeño

Error común 2: java.lang.StackOverflowError
Motivo del error: este también es un tipo de error de desbordamiento de memoria, es decir, el desbordamiento de la pila de subprocesos, ya sea porque hay demasiados niveles de llamadas a métodos (como infinitas llamadas recursivas), o la pila de subprocesos es demasiado pequeña.

Subproceso que ejecuta el diagnóstico 1: el uso de la CPU es demasiado alto:
obtenga el número de proceso y encuentre el proceso con un uso alto

top

Comando para obtener la identificación del proceso del hilo, la identificación del hilo, el uso de la CPU

ps H -eo pid,tid,%cpu | grep 进程号

Convierta el número de subproceso en un número hexadecimal: como 6626-> 19E2, obtenga la información de la pila del proceso y encuentre el subproceso con 'nid = 0X19E2'

jstack 进程id

El '#número' al comienzo del hilo del problema indica el número de líneas donde ocurre el problema, vuelva al código para verlo

Subproceso ejecutando el diagnóstico 2: problema de interbloqueo.
El programa se ejecuta durante mucho tiempo sin resultados. Puede ser un problema de interbloqueo.
Obtener información de la pila de procesos.

 jstack 进程id 

Verifique si hay un 'interbloqueo de nivel Java de fuente uno' en las últimas 20 líneas, verifique la descripción detallada del interbloqueo a continuación y localice el problema, y ​​luego
regrese al código para localizar el código para resolverlo.

②Error común de desbordamiento de memoria de pila (OutOfMemoryError)
: java.lang.OutOfMemoryError: Razón del error de espacio de pila de Java
: la memoria de pila de Java no es suficiente o hay un bucle infinito en el programa

Diagnóstico de memoria de almacenamiento dinámico:
generalmente use el análisis de archivos de volcado
Método 1: agregue parámetros para generar archivos cuando se inicie jvm
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/xxx/logs/
Método 2: exporte directamente
jmap -dump:file=filename.dump [ pid]

Puede usar el jvisualvm que viene con el JDK para analizar el archivo de volcado

③JVM ajusta tres parámetros principales
-Xss: especifica el tamaño de cada pila de máquina virtual de subprocesos (afecta la cantidad de subprocesos simultáneos) -Xms
: valor inicial del tamaño del almacenamiento dinámico (superar el valor inicial se expandirá al valor máximo)
-Xmx: almacenamiento dinámico tamaño Valor máximo (por lo general, el valor inicial es el mismo que el valor máximo, porque la expansión causará fluctuaciones en la memoria y afectará la estabilidad de la operación del programa) Fluctuaciones en la memoria:
cuando la memoria es insuficiente, se requiere el control de expansión y contracción, y cuando la la memoria es suficiente, la memoria en el área de expansión debe liberarse, lo que causará un impacto adicional en el rendimiento computacional. Puede establecer los parámetros de ejecución correspondientes para mejorar el rendimiento del programa, -Xmx: la memoria de inicialización máxima asignada, -Xms: la memoria asignada máxima, -Xmx menos -Xms es igual al tamaño del área de expansión, puede establecer los dos valores al mismo tamaño, mejoran el rendimiento.

2. Recolección de basura del GC

(1) Condiciones para la recolección de basura

Dónde ocurre la recolección de basura: el área de métodos y el montón en el área de datos de tiempo de ejecución son compartidos por subprocesos. El área de métodos recicla principalmente constantes descartadas y clases inútiles. La pila de la máquina virtual, la pila de métodos locales y el contador del programa están aislados por subprocesos. Entonces, lo que debe enfocarse es el montón.
Para juzgar si el objeto necesita recolección de basura:
① Preste atención al contador del programa, que se puede reciclar cuando el número de referencias es 0, pero no puede resolver la situación de referencia circular, por lo que no se usa comúnmente.
②Algoritmo de análisis de accesibilidad (utilizado por hotspot): depender de raíces gc (incluidos los atributos estáticos en el área de método/pila de la máquina virtual o constantes/objetos a los que hace referencia la interfaz nativa JNI-java en la pila de método local), no poder comunicarse con raíces gc se puede reciclar

(2) Tipo de referencia de Java

① Referencia fuerte: el tipo de referencia predeterminado en Java. Si un objeto tiene una referencia fuerte, no se procesará mientras la referencia aún exista.
②Referencia suave: en resumen, si un objeto tiene una referencia débil, el objeto no se procesará en GC antes de que se produzca el OOM de JVM (es decir, la memoria se utiliza por completo); el objeto se procesará en GC solo cuando la JVM no tenga suficiente memoria. Las referencias blandas se usan junto con una cola de referencia. Si el objeto al que hace referencia la referencia blanda se recicla, la referencia se agregará a la cola de referencia asociada a él. ③ Referencias
débiles (el enfoque de la clase Entry en ThreadLocalMap se analiza aquí ): Si el objeto solo tiene referencias débiles, el recolector de basura procesará el objeto (el objeto al que hace referencia la referencia débil solo puede sobrevivir hasta el próximo GC, cuando ocurra el GC, independientemente de si la memoria actual es suficiente, el el objeto al que hacen referencia los objetos de referencia débil se reciclará). Las referencias débiles también se utilizan junto con una cola de referencia.Si el objeto referenciado débilmente es reclamado por el período de recolección de basura, la JVM agregará esta referencia a la cola de referencia asociada con él. Si el objeto al que se hace referencia se puede obtener a través del método get de la referencia débil, cuando se recicla el objeto al que se hace referencia, llamar al método get devolverá un valor nulo ④
Referencia fantasma: la referencia fantasma es el tipo de referencia más débil entre todas las referencias, y su existencia es Para recibir una notificación después de que el objeto asociado con la referencia fantasma sea GCed. (El objeto señalado no se puede obtener a través del método get)

(3) flujo de procesamiento de GC

① La creación de instancias de objetos debe completarse con la palabra clave new. Todos los objetos nuevos se abren en Eden Park, y se producirá MinorGC (reciclado de GC de nueva generación) si la memoria en Eden Park es insuficiente.
② Si un objeto aún existe después de varios MinorGC, estos objetos ingresarán al área de supervivencia. Hay dos áreas de supervivencia, una es responsable de salvar los objetos sobrevivientes y la otra es responsable de la promoción. Las dos áreas se pueden transformar entre sí, y siempre habrá una memoria vacía.
③ Si el espacio no es suficiente, realice la recuperación de GC de generación anterior, ejecute MajorGC (Full GC, bajo rendimiento), si el espacio se puede recuperar, continúe con MinorGC.
④ Si MajorGC falla, la memoria se desborda y se informa una excepción OOM.
⑤Si el objeto recién creado es demasiado grande, se guardará directamente en la vejez.

(4) Algoritmo de recuperación de GC

Algoritmo de reciclaje de generación joven:
use el algoritmo de limpieza de copia (debido a que la eficiencia de supervivencia del objeto es baja, se usa este algoritmo con mayor eficiencia). Divida la memoria en varios bloques. Después de que se agote la memoria, copie el objeto vivo en otro bloque de memoria y el contenido superviviente se guardará en la generación anterior. La máquina virtual HotSpot (estándar JVM actual) utiliza tecnología BTP (todos los objetos se almacenan secuencialmente en la era de una sola CPU)/TLAB (dividida en diferentes bloques, dividida según el número de núcleos de CPU) para el procesamiento.

Algoritmo de reciclaje de vieja generación:
utilice el algoritmo de borrado de marcas. Marque la basura y límpiela de inmediato. Pausa la ejecución del programa durante el marcado para el análisis de accesibilidad. . Baja eficiencia y el problema de la fragmentación de la memoria.
Utilice el algoritmo de compresión de marcas. Según el algoritmo de borrado de marcas, toda la basura marcada se mueve a un extremo y luego se limpia.

Problema de referencia intergeneracional:
los objetos de la generación anterior apuntan a objetos de la nueva generación, y este objeto se reciclará por error durante la recolección de basura en la nueva generación. Solución: cree una colección de punteros de conjuntos de memoria en la nueva generación para registrar qué objetos en el área de la generación anterior apuntan a la nueva generación, en lugar de escanear toda el área de la generación anterior. Tenga en cuenta que lo que se registra es el área, no el objeto específico (alto costo de mantenimiento).Esta precisión es la precisión de la tarjeta, por lo que este conjunto de memoria se llama tabla de tarjetas, y cada elemento de la tabla de tarjetas corresponde a 512 bytes de la antigua generación. La tabla de tarjetas también debe mantenerse de forma dinámica. El punto de acceso mantiene la tabla de tarjetas a través de una barrera de escritura y genera una notificación circular cuando se produce una operación de asignación de un objeto de referencia. Coloque el código de mantenimiento en una barrera posterior a la escritura.

(5) Clasificación del recolector de basura

Los recolectores de basura se clasifican aproximadamente en recolectores en serie y recolectores paralelos: en serie significa un solo subproceso. A excepción de los recolectores de basura antiguos Serial/Serial que son seriales, el resto de los recolectores de basura son paralelos.

El principio de marcado concurrente en el colector paralelo:
el problema de la desaparición del objeto debe resolverse: durante el proceso de escaneo, un objeto (1) inserta una nueva referencia válida y (2) desconecta la referencia válida original.
Resuelva el problema (1): actualización incremental, registre nuevas referencias, vuelva a escanear la actualización incremental después del final del marcado concurrente: el recopilador de CMS usa
resolver el problema (2): instantánea original (SATB), registre la relación de referencia eliminada, concurrente Después del final, re- Juicio si hay otras referencias válidas para las referencias eliminadas: utilizado por el recopilador G1.

①Recolector de basura antiguo serie/serie: colector serie. De subproceso único, otros subprocesos deben detenerse durante la recolección de elementos no utilizados. La nueva generación adopta el algoritmo de copia (Serial), y la generación anterior adopta el algoritmo de marcado (Serial old).

②ParNew: Colector paralelo. Solo es responsable de la recolección de basura de la nueva generación. Excepto cuando el subproceso único se cambia a subprocesos múltiples en STW, los demás son consistentes con serail.
La generación anterior necesita usar serialOld o CMS. Para una CPU de un solo núcleo, serial es más eficiente que parNew.

③Recolector de basura CMS (intercambio de marcas concurrentes): la recolección concurrente tiene una pausa baja, la desventaja es que consume recursos de la CPU y no puede borrar la basura flotante.Si la memoria reservada en la generación anterior no es suficiente, fallará al mismo tiempo (serialold reemplazará cms para reciclar en este momento), Problemas de fragmentación de memoria: FULLGC ocurre cuando no se pueden satisfacer las asignaciones de objetos contiguos.
El uso de -XX:UseCMS-CompactAtFullCollection está habilitado de forma predeterminada y la desfragmentación de la memoria (compresión) se puede realizar cuando se produce el GC completo.
Use -XX:UseCMSFullGCsBeforeCompaction, el valor predeterminado es 0, y determine el proceso de comprimir
el marcado concurrente después de varias veces de Full GC: marcado inicial (juzgando si el objeto se puede conectar a raíces gc) - marcado concurrente - remarcado (corrección de puntos no preparados en el marcado concurrente, como el problema de desaparición de objetos) - limpieza concurrente. Cuando el marcado inicial y el remarcado requieran STW.

④Pararell Scavenge/Parallel old: Paralelo, de modo que la recolección de basura pueda alcanzar un estado que pueda controlar el rendimiento.
El enfoque de los recopiladores como CMS es acortar el tiempo de pausa de los subprocesos de usuario tanto como sea posible durante la recolección de basura, pero ralentizará la aplicación y reducirá el rendimiento total porque ocupa una parte del subproceso (o recursos de CPU) , mientras que Parallel Scavenge El objetivo del recopilador es lograr un rendimiento controlable (Throughput).
-XX:MaxGCPauseMills controla el tiempo máximo de pausa de la recolección de elementos no utilizados, -XX:GCTimeRatio controla el tamaño del rendimiento
-XXUseAdaptiveSizePolicy gc ajusta de forma adaptativa el tiempo de pausa y el rendimiento más adecuados.
Coopere con Parallel old para manejar la generación anterior. Utilícelo cuando se centre en el rendimiento y la sensibilidad a los recursos de la CPU.

⑤G1 Garbage Collector: admite memoria grande/admite múltiples CPU/reduce el tiempo STW (Stop the world, MajorGC marking time), lo que puede garantizar la ejecución de programas en estado concurrente. La principal diferencia con CMS es el principio de marcado concurrente.
Se usa por defecto después de JDK1.9, 1.7-1.8: -XX:+UseG1GC.

Usar con:
Serial+Serial Old
Parallel Scavenge+Paraller Old
ParNew+CMS

Nota: De manera predeterminada, JDK1.8 seleccionará diferentes estrategias de reciclaje de GC de acuerdo con los diferentes sistemas. Un solo núcleo es el reciclaje en serie y el multinúcleo es el reciclaje en paralelo. La operación predeterminada para JDK1.9-1.11 es G1.

2. Modelo de memoria Java

1. Conceptos básicos

JMM (modelo de memoria Java): es un conjunto de reglas para la visibilidad, el orden y la atomicidad de los datos cuando los subprocesos múltiples leen y escriben datos compartidos (tres elementos de programación concurrente).

2. palabra clave volátil

a. Visibilidad (la característica más importante). Una lectura de una variable volátil siempre ve la última escritura en la variable volátil por parte de cualquier subproceso.
b.Atomicidad. La lectura/escritura de cualquier variable volátil única (incluidos el tipo largo de 64 bits y el tipo doble) es atómica. Sin embargo, la operación compuesta de tipo a++/a = b no es atómica, y AtomicInteger (combinación de volátil y CAS) puede garantizar la atomicidad.
c) Ordenar, es decir, impedir la reordenación de instrucciones.

La palabra clave volátil evita que las instrucciones se reordenen a través de la "barrera de la memoria".Estrategia de
inserción de la barrera de la memoria:
inserte una barrera StoreStore delante de cada operación de escritura volátil (prohibiendo el reordenamiento de escrituras anteriores y escrituras volátiles).
Inserte una barrera StoreLoad después de cada operación de escritura volátil (no permitir el reordenamiento de escrituras volátiles con posibles lecturas y escrituras posteriores).
Inserte una barrera LoadLoad después de cada operación de lectura volátil (no permita el reordenamiento de lecturas volátiles con operaciones de lectura posteriores).
Inserte una barrera LoadStore después de cada lectura volátil (no permita el reordenamiento de lecturas volátiles con escrituras posteriores).
  Entre ellos, la barrera StoreLaod es la clave para garantizar la visibilidad, ya que eliminará todos los datos del búfer de escritura antes que la barrera de la memoria principal.

3. Comparación sincronizada, volátil, CAS

Sincronizado y bloqueado puede resolver los problemas de visibilidad, atomicidad y orden, volátil puede resolver el problema de visibilidad y orden, y atómico puede resolver el problema de atomicidad.

(1) sincronizado es un bloqueo pesimista, que es preventivo y hará que otros subprocesos se bloqueen.
(2) volatile proporciona visibilidad de variables compartidas de subprocesos múltiples y prohíbe la optimización del reordenamiento de instrucciones.
(3) CAS es un bloqueo optimista basado en la detección de conflictos (sin bloqueo)

Supongo que te gusta

Origin blog.csdn.net/tttalk/article/details/126734369
Recomendado
Clasificación