Área de método de área de datos de tiempo de ejecución de JVM (prefacio)

Área de método de área de datos en tiempo de ejecución

Prefacio

El área de método es la última parte del área de datos en tiempo de ejecución.
Inserte la descripción de la imagen aquí
Desde la perspectiva del uso compartido de subprocesos:
Inserte la descripción de la imagen aquí
ThreadLocal: ¿Cómo garantizar la seguridad de varios subprocesos en un entorno concurrente? Los escenarios típicos son la gestión de la conexión de la base de datos y la gestión de sesiones.

Interacción entre pila, montón y área de método

Lo siguiente involucra la ubicación de acceso del objeto:
Inserte la descripción de la imagen aquí

  • La información .class de la clase Person se almacena en el área de métodos;
  • La variable de persona se almacena en la tabla de variables locales de la pila de Java;
  • El objeto de persona real se almacena en el montón de Java;
  • En el objeto de persona, hay un puntero a los datos del tipo de persona en el área de método, lo que indica que el objeto de persona es nuevo de la clase Person en el área de método.

Comprensión del área de métodos

Documento oficial: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4

Dónde está el área de método:

  • La "Especificación de la máquina virtual de Java" establece claramente: Aunque todas las áreas de métodos son lógicamente parte del montón, algunas implementaciones simples pueden optar por realizar la recolección de basura o la compresión. Pero para HotSpot JVM, el área de método también tiene un alias llamado Non-Heap (non-heap), el propósito es separarse del montón.
  • Por lo tanto, el área de método se puede considerar como un espacio de memoria independiente del montón de Java .
    Inserte la descripción de la imagen aquí
    La comprensión básica del área de método : el área de método almacena principalmente la clase y el montón almacena principalmente los objetos instanciados.
  • El área de métodos, como el montón de Java, es un área de memoria compartida por todos los subprocesos. Cuando varios subprocesos cargan una sola clase al mismo tiempo, solo un subproceso puede cargar la clase, y otros subprocesos solo pueden esperar a que el subproceso termine de cargarse y luego usar la clase directamente, es decir, la clase solo se puede cargar una vez .
  • El área de método se crea cuando se inicia la JVM, y su espacio de memoria física real puede ser discontinuo como el área de almacenamiento dinámico de Java.
  • El tamaño del área del método, al igual que el espacio del montón, puede ser fijo o expandible.
  • El tamaño del área de método determina cuántas clases puede guardar el sistema. Si el sistema define demasiadas clases y el área de método se desborda, la máquina virtual también arrojará un error de desbordamiento de memoria: java.lang.OutofMemoryError: PermGen space o java. lang. OutOfMemoryError: Metaspace. Las siguientes situaciones pueden causar errores de desbordamiento de memoria:
    (1) Cargar una gran cantidad de paquetes jar de terceros;
    (2) Demasiados proyectos para la implementación de Tomcat (30-50);
    (3) Se genera una gran cantidad de clases de reflexión dinámica .
  • Cerrar la JVM liberará la memoria en esta área.

por ejemplo:

public class MethodAreaDemo {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("start...");
        try {
    
    
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        System.out.println("end...");
    }
}

¡El sencillo programa anterior carga más de 2000 clases! !
Inserte la descripción de la imagen aquí

Evolución del área del método HotSpot

  1. En JDK7 y antes, se acostumbra llamar al área de método la generación permanente. A partir de JDK8, la generación permanente ha sido reemplazada por metaspace. Podemos comparar el área de métodos con la interfaz en Java, y la generación permanente o metaespacio con la clase de implementación específica en Java;
  2. En esencia, el área de método y la generación permanente no son equivalentes. Solo para Hotspot puede considerarse equivalente. La "Especificación de máquina virtual de Java" no establece requisitos uniformes sobre cómo implementar el área de método. Por ejemplo: no existe el concepto de generación permanente en BEAJRockit / IBM J9;
  3. En JDK8, el concepto de generación permanente finalmente se abandonó por completo y se reemplazó con Metaspace, que se implementa en la memoria local como JRockit y J9;
  4. La naturaleza del metaespacio es similar a la generación permanente, y ambos son la realización del área de método en la especificación JVM. Sin embargo, la mayor diferencia entre el metaespacio y la generación permanente es que el metaespacio no está en la memoria configurada por la máquina virtual, sino que usa la memoria local ;
  5. Tanto la generación permanente como el metaespacio no solo han cambiado de nombre, sino que también han ajustado su estructura interna;
  6. De acuerdo con la "Especificación de la máquina virtual de Java", si el área de método no puede cumplir con los nuevos requisitos de asignación de memoria, se lanzará una excepción OOM.
    Inserte la descripción de la imagen aquí

Configuración del tamaño del área del método y OOM

No es necesario fijar el tamaño del área de método, la JVM se puede ajustar dinámicamente de acuerdo con las necesidades de la aplicación.

JDK7 y anteriores (generación permanente):

  • Utilice -XX: Permsize para establecer el espacio de asignación inicial de la generación permanente. El valor predeterminado es 20,75 M;
  • -XX: MaxPermsize para establecer el espacio máximo asignable de la generación permanente. El valor predeterminado es 64M para máquinas de 32 bits y 82M para máquinas de 64 bits;
  • Cuando la capacidad de la información de clase cargada por la JVM excede este valor, se notificará una excepción OutofMemoryError: PermGen space.
    Inserte la descripción de la imagen aquí

JDK8 y posterior (metaespacio):

  • El tamaño del área de metadatos se puede especificar con los parámetros -XX: MetaspaceSize y -XX: MaxMetaspaceSize.
  • El valor predeterminado depende de la plataforma. En Windows, -XX: MetaspaceSize es aproximadamente 21M, y el valor de -XX: MaxMetaspaceSize es -1, lo que significa que no hay límite.
  • A diferencia de la generación permanente, si no especifica el tamaño, la máquina virtual usa toda la memoria disponible del sistema de forma predeterminada. Si el área de metadatos se desborda, la máquina virtual también lanzará la excepción OutOfMemoryError: Metaspace.
  • -XX: MetaspaceSize: establece el tamaño del metaespacio inicial. Para una JVM del lado del servidor de 64 bits, el valor predeterminado -XX: MetaspaceSize es 21 MB. Esta es la marca de agua máxima inicial. Una vez que se toca esta marca de agua, se activará el GC completo y se descargarán las clases inútiles (es decir, el cargador de clases correspondiente a estas clases ya no está vivo), y luego se restablecerá esta marca de agua máxima . El valor de la nueva marca de agua alta depende de cuánto espacio se libera después de la GC. Si el espacio liberado es insuficiente, aumente el valor apropiadamente cuando no exceda MaxMetaspaceSize. Si el espacio libre es demasiado, reduzca el valor de forma adecuada.
  • Si la marca de agua alta inicializada se establece demasiado baja, el ajuste de la marca de agua alta mencionado anteriormente ocurrirá muchas veces. A través del registro del recolector de basura, se puede observar que Full GC se llama varias veces. Para evitar GC frecuente, se recomienda establecer -XX: MetaspaceSize en un valor relativamente alto.

Área de método OOM

Ejemplo de código: la clase OOMTest hereda la clase ClassLoader y obtiene el método defineClass (), que puede cargar la clase por sí mismo.

/**
 * jdk6/7中:
 * -XX:PermSize=10m -XX:MaxPermSize=10m
 *
 * jdk8中:
 * -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
 *
 */
public class OOMTest extends ClassLoader {
    
    
    public static void main(String[] args) {
    
    
        int j = 0;
        try {
    
    
            OOMTest test = new OOMTest();
            for (int i = 0; i < 10000; i++) {
    
    
                //创建ClassWriter对象,用于生成类的二进制字节码
                ClassWriter classWriter = new ClassWriter(0);
                //指明版本号,修饰符,类名,包名,父类,接口
                classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);
                //返回byte[]
                byte[] code = classWriter.toByteArray();
                //类的加载
                test.defineClass("Class" + i, code, 0, code.length);//Class对象
                j++;
            }
        } finally {
    
    
            System.out.println(j);
        }
    }
}

No establezca el límite superior del metaespacio: use los parámetros de JVM predeterminados y no establezca el límite superior para el metaespacio.
Resultado de salida:

10000

Establezca el límite superior del metaespacio: Parámetros: -XX: MetaspaceSize = 10m -XX: MaxMetaspaceSize = 10m
Resultado de salida:

8531
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
	at com.heu.method.OOMTest.main(OOMTest.java:29)

Cómo resolver OOM

Este es un problema de ajuste, hablemos brevemente de él aquí.

  1. Para resolver la anomalía de OOM o espacio de pila, el método general es analizar primero la instantánea de volcado de pila desde el volcado a través de una herramienta de análisis de imagen de memoria (como Ec1ipse MemoryAnalyzer), y el enfoque es confirmar si los objetos en la memoria son necesarios , es decir, primero debemos distinguir si hay una fuga de memoria (Memory Leak) o un desbordamiento de memoria (Memory Overflow);
  2. La fuga de memoria es que hay una gran cantidad de referencias a ciertos objetos, pero estos objetos no se usarán en el futuro, pero debido a que todavía están asociados con GC ROOT, estos objetos no se reciclarán en el futuro. Este es el problema de pérdidas de memoria;
  3. Si se trata de una pérdida de memoria, puede verificar más a fondo la cadena de referencia del objeto filtrado a las raíces del GC a través de la herramienta. Luego, puede averiguar cómo los objetos filtrados están relacionados con GC Roots y hacer que el recolector de basura no pueda recolectarlos automáticamente. Conociendo el tipo de información del objeto filtrado y la información de la cadena de referencia de GCRoots, puede localizar la ubicación del código filtrado con mayor precisión.
  4. Si no hay pérdida de memoria, en otras palabras, todos los objetos en la memoria deben seguir vivos, entonces los parámetros del montón de la máquina virtual (-Xmx y -Xms) deben verificarse y compararse con la memoria física de la máquina para ver si Desde el código, compruebe si hay algunos objetos con un ciclo de vida demasiado largo y un estado de retención durante demasiado tiempo, e intente reducir el consumo de memoria durante la ejecución del programa.

Supongo que te gusta

Origin blog.csdn.net/qq_33626996/article/details/114270507
Recomendado
Clasificación