[Conceptos básicos de JVM] Conceptos básicos de JVM

La ubicación de la JVM

La aplicación (aplicación Java) se ejecuta en el JRE (JRE contiene la JVM), el JRE se ejecuta en el sistema operativo (Windows, Mac) y el sistema operativo se ejecuta en la arquitectura de hardware (Intel, Spac...).

Tres JVM

  • Sun: HotSpot es el más usado (nosotros usamos)
  • BEA: JRockit
  • IBM: J9VM

arquitectura JVM

Ajuste de JVM: el 99% está en el área de método y el montón, la mayor parte del tiempo el montón está ajustado. JNI (Java Native Interface): interfaz de método nativo
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

cargador de clases

Función: cargar el archivo de clase.
Por ejemplo: new Student();(la instancia específica está en el montón y el nombre de la variable de referencia se coloca en la pila)

  • El cargador que viene con la máquina virtual.
  • Inicie el cargador de clases (raíz)
  • cargador de clases de extensión
  • cargador de aplicaciones

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Mecanismo de delegación de los padres

concepto

Cuando un cargador de clases necesita cargar un determinado archivo .class, primero confía esta tarea a su cargador de clases superior y realiza esta operación de forma recursiva. Si el cargador de clases superior no lo carga, cargará la clase misma.

ejemplo

Hello.classCuándo se va a cargar dicho archivo .
Independientemente de nuestro cargador de clases personalizado, primero verificaremos si se ha cargado en AppClassLoader y, de ser así, no es necesario volver a cargarlo. De lo contrario, se obtendrá el cargador principal y se llamará al método loadClass del cargador principal .
De la misma manera, la clase padre primero verificará si se ha cargado y, si no, subirá. Tenga en cuenta que este proceso recursivo, hasta que llega al cargador de clases Bootstrap , verifica si se ha cargado y no elegirá cargarlo solo.
Hasta BootstrapClassLoader , no hay ningún cargador principal. En este momento, empiezo a pensar si puedo cargarlo. Si no puedo cargarlo, me hundiré en el cargador secundario para cargarlo, hasta que llegue al final. Si no hay ningún cargador que pueda cargarlo, arrojará ClassNotFoundException.

inserte la descripción de la imagen aquí

efecto

  • 1. Evite la carga repetida de la misma .class. Pregunte lo anterior mediante encomienda, después de cargarlo, no es necesario volver a cargarlo. Garantizar la seguridad de los datos.
  • 2. Asegúrese de que core.class no pueda ser manipulado. A través de la delegación, el .class principal no será manipulado, incluso si se manipula, no se cargará, e incluso si se carga, no será el mismo objeto .class. Diferentes cargadores cargan el mismo .class y no son el mismo objeto Class. Esto garantiza la seguridad de la ejecución de la clase.

Por ejemplo: si alguien quiere reemplazar la clase a nivel de sistema: String.java.
Alterando su implementación, bajo este mecanismo, las clases de estos sistemas han sido cargadas por Bootstrap ClassLoader (¿por qué? Porque cuando es necesario cargar una clase, lo primero que se intenta cargar es BootstrapClassLoader), por lo que otros cargadores de clases no son El La posibilidad de volver a cargar impide en cierta medida la implantación de códigos peligrosos.

Mecanismo de seguridad de la zona de pruebas

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Componentes básicos que componen un sandbox

  • El verificador de código de bytes
    garantiza que el archivo de clase Java .Class siga las especificaciones del lenguaje Java. Esto ayuda a los programas Java a lograr protección de la memoria. Pero no todos los archivos de clase se someterán a una verificación de código de bytes, como las clases principales.
  • Cargador de clases (cargador de clases)
    donde el cargador de clases funciona en el entorno limitado de Java de tres maneras:
    • Evita que el código malicioso interfiera con el código de buena fe; //Modo de delegación de padres
    • Protege los límites de las bibliotecas confiables;
    • Coloca el código en dominios de protección, lo que determina lo que puede hacer el código.

La máquina virtual proporciona diferentes espacios de nombres para las clases cargadas por diferentes cargadores de clases. El espacio de nombres consta de una serie de nombres únicos. Cada clase cargada tendrá un nombre. Este espacio de nombres es creado por la máquina virtual Java para cada uno mantenido por el cargador de clases, ellos ni siquiera son visibles el uno para el otro.

El mecanismo utilizado por el cargador de clases es el modelo de delegación parental .

1. Comience a cargar desde el cargador de clases de la JVM más interna, y la clase maliciosa externa con el mismo nombre no se puede cargar ni usar;

2. Dado que el dominio de acceso se distingue estrictamente por el paquete, la clase maliciosa en la capa externa no puede obtener permiso para acceder a la clase interna a través del código incorporado y, naturalmente, el código dañado no tendrá efecto.

  • Controlador de acceso (controlador de acceso): el controlador de acceso puede controlar la autoridad de acceso de la API principal al sistema operativo, y el usuario puede especificar la configuración de política de este control.
  • Administrador de seguridad (administrador de seguridad): es la interfaz principal entre la API central y el sistema operativo. Para implementar el control de permisos, tiene una prioridad más alta que el controlador de acceso.
  • Paquete de seguridad: las clases de java.security y las clases del paquete de extensión, que permiten a los usuarios agregar nuevas funciones de seguridad a sus aplicaciones, que incluyen:
    • proveedor de seguridad
    • resumen del mensaje
    • Herramientas clave de firma digital https (se requiere certificado)
    • cifrado
    • identificar

Nativo

Aquellos con la palabra clave nativa indican que no se puede alcanzar el alcance de Java y debe regresar para llamar a la biblioteca subyacente del lenguaje C.
Cualquier método con la palabra clave nativa ingresará a la pila de métodos locales , y los demás son la pila de Java.

JNI: Interfaz nativa de Java (interfaz de método local)

La función de llamar a la interfaz del método local (JNI):

Ampliar el uso de Java e integrar diferentes lenguajes de programación para Java. La
intención original de Java era integrar programas C/C++. C y C++ están muy extendidos. Si desea afianzarse, debe tener programas que llamen a C y C ++. Está especialmente desarrollado en el área de memoria de la ciudad. Ciudad del distrito de marcado de bloques: pila de métodos nativos

Pila de métodos nativos

Registre el método nativo, cuando se ejecute el motor de ejecución (Execution Engine). Cargue métodos en **Bibliotecas nativas** a través de JNI (interfaz de método nativo).

Raro en aplicaciones de nivel empresarial, aplicaciones relacionadas con hardware: impresoras basadas en programas Java, equipos de producción de gestión de sistemas, etc.

Registro de PC (registro de contador de programa)

Contador de programa: Registro del contador de programa

Cada hilo tiene un contador de programa, que es privado para el hilo y es un puntero al código de bytes del método en el área del método (utilizado para almacenar la dirección que apunta a la siguiente instrucción, que también es el código de instrucción que se ejecutará), en el motor de ejecución Leer la siguiente instrucción ocupa un espacio de memoria muy pequeño, casi insignificante.

Área del método

El área del método es compartida por todos los subprocesos . Todos los campos y códigos de bytes de los métodos, así como algunos métodos especiales, como constructores y códigos de interfaz, también se definen aquí. En pocas palabras: toda la información del método definido se almacena en esta área, que pertenece al área compartida. espacio;

Las variables estáticas, las constantes, la información de clase (método de construcción, definición de interfaz), el grupo de constantes de tiempo de ejecución (como: estático, final, clase (plantilla de clase), grupo de constantes) se almacenan en el área de métodos, pero las variables de instancia se almacenan en el montón . memoria No tiene nada que ver con el área del método.

Pila (pila Java)

Por qué main() se ejecuta primero y finaliza al final: (porque main() se inserta primero en la pila)

Pila: memoria de pila, ejecución del programa supervisor, ciclo de vida y sincronización de subprocesos.
Cuando finaliza el hilo, se libera la memoria de la pila y no hay problema de recolección de basura para la pila.

Almacenamiento de pila: 8 tipos básicos + referencia de objeto + método de instancia.
Principio de operación de la pila: el marco de la pila (tabla de variables locales + pila de operandos) tiene un marco de pila para cada método llamado.
La pila está llena y main() no puede finalizar, se generará un error: desbordamiento de pilaStackOverflowError

inserte la descripción de la imagen aquí

Pila + montón + área de método: relación interactiva

inserte la descripción de la imagen aquí

Montón

Una JVM tiene solo una memoria de montón y el tamaño del montón se puede ajustar.
Después de que el cargador de clases lee el archivo de clase, generalmente coloca clases, métodos, constantes, variables y objetos reales que guardan todos los tipos de referencia en el montón.

La memoria del montón se subdivide en 3 áreas:

  • Nuevo Distrito (Distrito Eden) Joven / nuevo
  • zona de retiro antigua
  • Área permanente Perm, después de JDK8, el área de almacenamiento permanente ha cambiado su nombre (metaespacio)

Recolección de basura de GC, principalmente en Eden Park y áreas de retiro.
inserte la descripción de la imagen aquí
Suponiendo que la memoria está llena, se informa un error OOM: no hay suficiente memoria de montónOutOfMemoryError:Java heap space

//-Xms8m -Xmx8m -XX:+PrintGCDetails
public static void main(String[] args) {
    
    
    String str = "javajavajavajava";

    while (true){
    
    
        str += str + new Random().nextInt(888888888)+ new Random().nextInt(21_0000_0000);
    }
}
//OutOfMemoryError:Java heap space 堆内存满了

inserte la descripción de la imagen aquí

Área de recién nacidos (Jardín del Edén + Área de sobrevivientes*2)

  • Un lugar donde las clases nacen, crecen e incluso mueren.
  • Jardín del Edén, todos los objetos son de nueva creación en el Jardín del Edén.
  • Área de supervivientes (desde, hasta), el GC ligero limpia regularmente el Jardín del Edén, y los que sobreviven son colocados en el área de supervivientes. Una vez que el área de supervivientes está llena, el GC pesado limpia el área de Eden+survivor , y el los supervivientes son trasladados a la zona de retiro. Si están llenos reportar OOM.

Nota: Después de la investigación, ¡el 99% de los objetos son objetos temporales! limpiado directamente

Zona de mayores

El resto de la nueva área, el GC ligero no puede matar.

área permanente

Esta área reside en la memoria y se utiliza para almacenar los objetos de clase y los metadatos de la interfaz que lleva el propio JDK. Almacena cierta información del entorno o de la clase del tiempo de ejecución de Java. No hay GC de recolección de basura en esta área . Al apagar la máquina virtual se libera esta memoria.

  • Antes de jdk1.6: generación permanente, el grupo constante está en el área del método .
  • jdk1.7: generación permanente, pero degenera lentamente (a generación permanente), el grupo constante está en el montón .
  • Después de jdk1.8: no hay generación permanente y el grupo constante está en el metaespacio .

El grupo de constantes siempre ha estado en el área de métodos y el grupo de cadenas que contiene se guardó en el montón después de JDK1.7.

Ejemplo de OOM de área permanente: una clase de inicio que carga una gran cantidad de paquetes jar de terceros. Tomcat implementa demasiadas aplicaciones y una gran cantidad de clases de reflexión generadas dinámicamente. Estando constantemente cargado. Hasta que la memoria esté llena, aparecerá OOM.

El área del método también se llama no montón, que en esencia sigue siendo un montón, solo para distinguir conceptos.

El metaespacio existe lógicamente, pero no físicamente.

Ajuste de la memoria del montón

public static void main(String[] args) {
    
    
    //返回虚拟机试图使用的最大内存
    long max = Runtime.getRuntime().maxMemory(); //字节 1024*1024
    //返回jvm初始化的总内存
    long total = Runtime.getRuntime().totalMemory();

    System.out.println("max="+max+"字节\t"+(max/(double)1024/1024+"MB"));
    System.out.println("total="+total+"字节\t"+(total/(double)1024/1024+"MB"));
    /* 运行后:
    max=1866465280字节   1780.0MB
    total=126877696字节  121.0MB
     */
    //默认情况下,分配的总内存占电脑内存1/4 初始化1/64
}

¿Cómo reportar OOM?

  • 1. Intente expandir la memoria del montón. Si el error aún se informa, significa que hay un código de bucle infinito o un código basura. Edite
    configuración>agregar opción VM> Entrada: -Xms1024m -Xmx1024m -XX:+PrintGCDetails
    inserte la descripción de la imagen aquí
    área de recién nacido + área de vejez: 305664K+699392K=1005056K = 981,5M, lo que indica que la física metaespacial no existe.

  • 2. Analice la memoria y vea dónde hay un problema (herramientas profesionales)
    para ver qué líneas de código están incorrectas: herramienta de análisis de instantáneas de memoria, MAT, Jprofiler
    MAT, función Jprofiler:

    • Analizar archivos de memoria de volcado para localizar rápidamente pérdidas de memoria;
    • obtener los datos en el montón
    • conseguir objeto grande
//-Xms 设置初始化内存分配大小 默认1/64
//-Xmx 设置最大分配内存,默认1/4
//-XX:+PrintGCDetails 打印GC垃圾回收信息
//-XX:+HeapDumpOnOutOfMemoryError //oom DUMP
//-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
public class Demo03 {
    
    
    byte[] array = new byte[1*1024*1024]; //1m

    public static void main(String[] args) {
    
    
        ArrayList<Demo03> list = new ArrayList<>();
        int count = 0;
        try {
    
    
            while (true){
    
    
                list.add(new Demo03()); //不停地把创建对象放进列表
                count = count + 1;
            }
        } catch (Exception e) {
    
    
            System.out.println("count: "+count);
            e.printStackTrace();
        }
    }
}

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

GC (recolección de basura)

inserte la descripción de la imagen aquí
Cuando la JVM realiza GC, no recicla uniformemente las tres áreas de la nueva generación, el área superviviente y el área antigua. La mayoría de las veces, la nueva generación se recicla.

Dos tipos de GC: GC ligero, GC pesado (GC completo, GC global)

conteo de referencia

Generalmente no se utiliza JVM, hay demasiados objetos de proyecto grandes
inserte la descripción de la imagen aquí

algoritmo de copia

-XX:MaxTenuringThreshold=15Establezca el número de condiciones de supervivencia para ingresar a la vejez.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Ventajas: sin fragmentación de la memoria, alta eficiencia de la memoria
Desventajas: se desperdicia espacio de memoria (un área superviviente siempre está vacía); suponiendo que el objeto está 100% vivo, el costo de la copia es alto.
El mejor escenario de uso del algoritmo de replicación: cuando la supervivencia del objeto es baja, se crea una nueva área.

marcar claro

inserte la descripción de la imagen aquí
Ventajas: no se requiere espacio adicional y el algoritmo de copia está optimizado.
Desventajas: dos escaneos, una gran pérdida de tiempo, generarán fragmentación de la memoria.

Compresión de etiquetas (limpieza de marcas): reoptimización

Trilogía: Marcar – Borrar – Comprimir
inserte la descripción de la imagen aquí

Compresión de barrido de marcas: reoptimización

Comprimir cada vez que se borre la marca o si la fragmentación de la memoria se acumula hasta cierto punto.

Algoritmo de recopilación generacional

Según el ciclo de vida del objeto de memoria, la memoria se divide en varias partes y la JVM generalmente divide la memoria en la nueva generación y la antigua generación.
En la nueva generación, una gran cantidad de objetos muere y una pequeña cantidad de objetos sobrevive, por lo que el algoritmo de copia puede usarse para completar la colección solo pagando el costo de copiar una pequeña cantidad de objetos sobrevivientes; en la generación anterior, porque la tasa de supervivencia de los objetos es extremadamente alta y no hay espacio adicional para
ellos. Se realiza una garantía de asignación, por lo que se utiliza un algoritmo de limpieza o clasificación de marcas para el reciclaje;
inserte la descripción de la imagen aquí

Resumir

Eficiencia de la memoria: Algoritmo de replicación > Algoritmo de barrido de marcas > Algoritmo de compresión de marcas (complejidad de tiempo)

Uniformidad de la memoria: algoritmo de copia = algoritmo de compresión de marcas> algoritmo de eliminación de marcas

Utilización de la memoria: Algoritmo de compresión de marcas = Algoritmo de borrado de marcas > Algoritmo de copia

No existe el mejor algoritmo, solo un algoritmo adecuado (GC también se conoce como algoritmo de recopilación generacional).

  • Generación joven: la tasa de supervivencia es baja y se utiliza el algoritmo de replicación.
  • Vieja generación: alta tasa de supervivencia, área grande, marcar-borrar-comprimir.

Supongo que te gusta

Origin blog.csdn.net/qq_44033208/article/details/132470273
Recomendado
Clasificación