Comprensión en profundidad de las notas de estudio 1 de la máquina virtual de Java (área de memoria de Java y excepción de desbordamiento de memoria)

1. Área de datos durante el tiempo de ejecución de la máquina virtual Java


Área de datos compartida por todos los subprocesos: Montón, Área de método Área
de datos aislados de subproceso: Pila de VM, Pila de método nativo, Registro de contador de programa
1.1 En el modelo conceptual, el intérprete de código de bytes funciona cambiando el valor del contador de programa del subproceso actual A seleccione la siguiente instrucción de código de bytes que se ejecutará
1.2 La pila de la máquina virtual sirve a la máquina virtual para ejecutar el método java. Cuando se ejecuta cada método, se crea una pila de marcos para almacenar la tabla de variables locales, la pila de operaciones, el enlace dinámico y la salida del método Y otra información.
El proceso desde el momento en que se llama a cada método hasta la finalización de la ejecución corresponde al proceso de una pila de marcos desde que se empuja hasta que aparece en la pila de la máquina virtual.
1.3 La pila de métodos locales ejecuta el servicio de métodos locales para la máquina virtual.
1.4 El montón se crea cuando se inicia la máquina virtual. El único propósito de esta área de memoria es almacenar instancias de objetos. El montón se puede subdividir en la nueva generación y la antigua generación
1.5 Área de métodos para almacenar máquinas virtuales Datos tales como información de clase, constantes, variables estáticas y código compilado por el compilador just-in-time cargado por la máquina.

2. Acceso a objetos

Hay dos métodos principales de acceso a objetos: mediante identificadores y punteros directos

3. El combate real es anormal

3.1 desbordamiento del montón de Java

/**
 * @Title: HeapOOM
 * @Description: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/home/
 * @date 2020/4/15 17:57
 */
public class HeapOOM {
    static class OOMObject{}

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while (true){
            list.add(new OOMObject());
        }
    }
}

resultado de la operación:

3.2 Desbordamiento de pila de máquina virtual y método nativo

/**
 * @Title: JavaVMStackSOF
 * @Description: -verbose:gc -Xms20M -Xss128K -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/home/
 * @date 2020/4/16 9:08
 */
public class JavaVMStackSOF {
    private int stackLength = 1;

    private void stackLeak(){
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }
}

El resultado de la operación es solo StackOverflowError

3.3 La creación de un hilo provoca un desbordamiento de la memoria

/**
 * @Title: javaVMStackOOM
 * @Description: -verbose:gc -Xms20M -Xss2M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/home/
 * @date 2020/4/16 9:33
 */
public class JavaVMStackOOM {
    private void dontStop(){
        while (true){}
    }

    public void stackLeakByThread(){
        while (true){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    dontStop();
                }
            });
            thread.start();
        }
    }

    public static void main(String[] args) {
        JavaVMStackOOM oom = new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}

Es fácil bloquearse después de ejecutarse y no hay ningún resultado cuando se ejecuta.

3.4 Desbordamiento constante de la piscina en tiempo de ejecución

Al probar el código de desbordamiento en el área de método de acuerdo con el documento 2.4.3, se encontró que había pasado mucho tiempo y no se produjo ningún desbordamiento de memoria. Después de leer el documento, supe que el código permanente se eliminó después de jdk1.7.

// - XX: PermSize = 10M -XX: MaxPermSize = 10M 
public class RuntimeConstantPoolOOM { 
    public static void main (String [] args) { 
        List <String> list = new ArrayList <> (); 
        int i = 0; 
        while (verdadero) { 
            list.add (String.valueOf (i ++). intern ()); 
        } 
    } 
}

Antes de aquí, además del código compilado justo a tiempo almacenado en la memoria nativa, otros datos, incluida la información de clase, constantes, variables estáticas, grupos de constantes, etc., se almacenan en la generación permanente. Sin embargo, hay un problema en de esta forma, es decir, es probable que se produzcan pérdidas de memoria.

Por lo tanto, en jdk8, la generación permanente se elimina por completo y se reemplaza por metaSpace. El concepto de área de método se mantiene en el metaespacio y el grupo de constantes está en el montón.

El área de métodos es solo un concepto definido en la especificación JVM . Se utiliza para almacenar datos como información de clases, grupos de constantes, variables estáticas y código compilado JIT. Donde se coloca, se pueden colocar diferentes implementaciones en diferentes lugares. La generación permanente es un concepto único de la máquina virtual Hotspot , que es una implementación del área de métodos, que no está disponible en otras JVM.

Antes de jdk1.7: el área de método se encuentra en la generación permanente (PermGen). La generación permanente y el montón están aislados entre sí. El tamaño de la generación permanente se puede establecer en un valor fijo cuando se inicia la JVM, y es inmutable;
jdk.7: Parte de los datos almacenados en la generación permanente se acaba de transferir a Java Heap o memoria nativa. Sin embargo, la generación permanente todavía existe en JDK 1.7 y no se ha eliminado por completo. Por ejemplo, las referencias de símbolos (Símbolos) se transfieren a la memoria nativa; las cadenas internas se transfieren al montón de Java; las variables de clase estática se transfieren. Al montón de Java ;
jdk1.8: El concepto de área de método aún se conserva, pero la implementación es diferente. Cancele la generación permanente y el método se almacena en el metaespacio. El metaespacio aún no está conectado al montón, pero comparte memoria física con el montón, que lógicamente se puede considerar que está en el montón.

1) Eliminó la generación permanente (PermGen) y la reemplazó con Metaspace;
2) Los metadatos de la clase en la generación permanente fueron transferidos a la memoria nativa (memoria local, no máquina virtual);
3) Interned Strings y la generación permanente Las variables estáticas de la clase se transfieren al montón de Java;
4) Parámetro de generación permanente (PermSize MaxPermSize) -> Parámetro Metaspace (MetaspaceSize MaxMetaspaceSize).

3.5 Desbordamiento del área de método

public class JavaMethodAreaOOM { 
    static class OOMObject {} 

    public static void main (String [] args) { 
        while (true) { 
            Enhancer enHancer = new Enhancer (); 
            enHancer.setSuperclass (OOMObject.class); 
            enHancer.setUseCache (falso); 
            enHancer.setCallback (new MethodInterceptor () { 
                @Override 
                public Object intercept (Object o, Method method, Object [] args, MethodProxy methodProxy) throws Throwable { 
                    return methodProxy.invoke (o, args); 
                } 
            }); 
        } 
    } 
}

Parámetros de la máquina virtual jdk1.7: -XX: PermSize = 10M -XX: MaxPermSize = 10M 

resultado de la operación:

Parámetros de la máquina virtual jdk1.8: -XX: MetaspaceSize = 10M -XX: MaxMetaspaceSize = 10M

resultado de la operación:

El desbordamiento del montón del resultado de la operación jdk1.7 indica que la información de la clase se coloca en el montón.

El desbordamiento de Metaspace del resultado de ejecución de jdk1.8 indica que la información de la clase está realmente ubicada en el Metaspace.

3.6 Desbordamiento de memoria directa nativa

// - Xmx20M -XX: MaxDirectMemorySize = 10M 
public class DirectMemoryOOM { 
    privado estático final int _1M = 1024 * 1024; 

    public static void main (String [] args) arroja Exception { 
        Field unsafeField = Unsafe.class.getDeclaredFields () [0]; 
        unsafeField.setAccessible (verdadero); 
        Inseguro inseguro = (Inseguro) unsafeField.get (nulo); 
        while (verdadero) { 
            inseguro.allocateMemory (_1M); 
        } 
    } 
}

resultado de la operación:

Supongo que te gusta

Origin blog.csdn.net/noob9527/article/details/105559659
Recomendado
Clasificación