Conocimientos básicos de Java JVM-6 clases de OOM de demostración de OutOfMemoryError

Demostración de OutOfMemoryError

El primero, StackOverflowError

Este error se producirá cuando la pila esté llena. La recursividad infinita causará StackOverflowError, que es un error en java.lang.Throwablejava.lang.Errorjava.lang.VirtualMachineError.

Código

package jvm;

public class StackOverflowErrorDemo {
    
    
    public static void main(String[] args) {
    
    
        stackOverflowError();
    }

    private static void stackOverflowError() {
    
    
        stackOverflowError();
    }

}

Salida

Exception in thread "main" java.lang.StackOverflowError
	at jvm.StackOverflowErrorDemo.stackOverflowError(StackOverflowErrorDemo.java:9)
	at jvm.StackOverflowErrorDemo.stackOverflowError(StackOverflowErrorDemo.java:9)

El segundo, espacio dinámico de Java

Este error se producirá cuando la pila esté llena.
En IDEA菜单栏---Run---Edit Configurations ---VM optionsrelleno en los siguientes parámetros

-Xms10m -Xmx10m

Finalmente, haga clic derecho para ejecutar.

Código

package jvm;

import java.util.Random;

//-Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
public class JavaHeapSpaceDemo {
    
    
    public static void main(String[] args) {
    
    
        String str = "adf";
        while (true) {
    
    
            str += str + new Random().nextInt(1111111) + new Random().nextInt(222222);
            str.intern();
        }
    }
}

Salida

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3332)
	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:674)
	at java.lang.StringBuilder.append(StringBuilder.java:208)
	at jvm.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:10)

Se superó el límite de gastos generales de GC

Cuando el tiempo de recolección de GC es demasiado largo, se producirá un error outofMemroyError. La definición de demasiado largo es que el 98% del tiempo se usa para GC y se
recupera menos del 2% del montón . Si hay varios GC consecutivos, solo se lanzará cuando se recupere menos del 2%. ¿Qué sucede si no se produce el error de límite de sobrecarga del GC?
Es decir, el GC limpia una cantidad tan pequeña de memoria que se llenará nuevamente y el GC se ejecutará nuevamente, lo que formará un círculo vicioso. La
tasa de uso de la CPU es siempre del 100%. GC Pero sin resultados

Código

package jvm;

import java.util.ArrayList;
import java.util.List;

//-Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
public class GCOverheadDemo {
    
    
    public static void main(String[] args) {
    
    
        int i = 0;
        List<String> list = new ArrayList<>();
        try {
    
    
            while (true) {
    
    
                list.add(String.valueOf(++i).intern());
            }
        } catch (Exception e) {
    
    
            System.out.println("************i" + i);
            e.printStackTrace();
            throw e;
        }
    }
}


GCOverheadLimit
Detalles de salida

[GC (Allocation Failure) [PSYoungGen: 2035K->496K(2560K)] 2035K->1020K(9728K), 0.0016816 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 2544K->505K(2560K)] 3068K->2701K(9728K), 0.0024345 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 2553K->512K(2560K)] 4749K->4593K(9728K), 0.0030155 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 2560K->496K(2560K)] 6641K->6650K(9728K), 0.0037446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 496K->0K(2560K)] [ParOldGen: 6154K->6218K(7168K)] 6650K->6218K(9728K), [Metaspace: 3214K->3214K(1056768K)], 0.0721823 secs] [Times: user=0.27 sys=0.00, real=0.07 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2048K->824K(2560K)] [ParOldGen: 6218K->7020K(7168K)] 8266K->7845K(9728K), [Metaspace: 3214K->3214K(1056768K)], 0.0489867 secs] [Times: user=0.23 sys=0.00, real=0.05 secs] 
...
...
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7061K->7061K(7168K)] 9109K->9109K(9728K), [Metaspace: 3218K->3218K(1056768K)], 0.0330914 secs] [Times: user=0.13 sys=0.00, real=0.03 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7063K->7063K(7168K)] 9111K->9111K(9728K), [Metaspace: 3218K->3218K(1056768K)], 0.0327293 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7065K->7065K(7168K)] 9113K->9113K(9728K), [Metaspace: 3218K->3218K(1056768K)], 0.0278034 secs] [Times: user=0.20 sys=0.00, real=0.03 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7067K->7067K(7168K)] 9115K->9115K(9728K), [Metaspace: 3218K->3218K(1056768K)], 0.0292778 secs] [Times: user=0.22 sys=0.00, real=0.03 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2047K->0K(2560K)] [ParOldGen: 7092K->614K(7168K)] 9140K->614K(9728K), [Metaspace: 3249K->3249K(1056768K)], 0.0072447 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 2560K, used 166K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 8% used [0x00000000ffd00000,0x00000000ffd29ad0,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 7168K, used 614K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 8% used [0x00000000ff600000,0x00000000ff699b60,0x00000000ffd00000)
 Metaspace       used 3325K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 359K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.lang.Integer.toString(Integer.java:403)
	at java.lang.String.valueOf(String.java:3099)
	at jvm.GCOverheadDemo.main(GCOverheadDemo.java:13)

Memoria intermedia directa

La escritura de programas NIO a menudo usa ByteBuffer para leer o escribir datos. Este es un método de E / S basado en canales (canal) y búfer (búfer) .
Puede usar la biblioteca de funciones nativas para asignar directamente la memoria fuera del montón y luego pasar una DirectByteBuffer0 en Java funciona como una referencia a esta memoria, lo que
puede mejorar significativamente el rendimiento en algunos escenarios, ya que evita la copia de datos entre Jva y montones nativos.
ByteBuffer.allocate( capability)El primer método consiste en asignar memoria W, que está bajo la jurisdicción de GC. Debido a la necesidad de shells, la velocidad es relativamente lenta
ByteBuffer.allocateDirect( capability). El primer método consiste en asignar memoria local del SO, que no está dentro del alcance de la administración de GC. Debido a la necesidad de copia de memoria, la velocidad es relativamente lenta. Rápido
Pero si sigue asignando memoria local y la memoria de inserción rara vez se usa, entonces W no necesita realizar GC, los objetos DirectByte Buffer no se reciclarán,
hay suficiente memoria, pero es posible que la memoria local se haya agotado, y luego intente asignar memoria local 0ut0 mEmory Error aparecerá y el programa se bloqueará directamente.

Código

package jvm;

import java.nio.ByteBuffer;

//-Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
public class DirectBufferMemoryDemo {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("配置的maxDirectMemory: " 
        + (sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024) + "MB");
        try {
    
    
            Thread.sleep(300);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
    }
}

OOM: no se puede crear un nuevo hilo nativo

En escenarios de alta simultaneidad, si el número de subprocesos creados excede el número máximo de subprocesos predeterminado del sistema, se lanzará esta excepción. De forma predeterminada, un solo proceso de Linux no puede superar los 1024 subprocesos. La solución es reducir el número de subprocesos del programa o modificar el número máximo de subprocesos en el sistema vim /etc/security/limits.d/90-nproc.conf.

package jvm;

public class UnableCreateNewThreadDemo {
    
    
    public static void main(String[] args) {
    
    
        for (int i = 0; ; i++) {
    
    
            System.out.println("***********" + i);
            new Thread(() -> {
    
    
                try {
    
    
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }, "" + i).start();
        }
    }
}

Salida

***********0
***********1
...
...
***********47842
***********47843
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
	at java.lang.Thread.start0(Native Method)
	at java.lang.Thread.start(Thread.java:717)
	at jvm.UnableCreateNewThreadDemo.main(UnableCreateNewThreadDemo.java:13)

OOM: Metaspace

Esta excepción se lanzará cuando el metaespacio esté lleno.

Código

package jvm;


import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * java 8及之后版本使用Metaspace来代替永久代
 * -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
 *
 * 永久代(java8使用Metaspace)存放的信息:
 * 虚拟机加载的类信息
 * 常量池
 * 静态变量
 * 即时编译后的代
 *
 * 模拟Metaspace空间溢出,我们不断生成类往空间灌,类占据的空间总是会超时Metaspace指定的空间大小的
 */
public class MetaspaceOOMTest {
    
    

    static class OOMTest {
    
    
    }

    public static void main(String[] args) {
    
    
        int i = 0;
        try {
    
    
            while (true) {
    
    
                i++;
                // 使用CGLIB生成代理:
                // 1.创建核心类:
                Enhancer enhancer = new Enhancer();
                // 2.为其设置父类:
                enhancer.setSuperclass(OOMTest.class);
                // 3.设置回调:
                enhancer.setCallback(new MethodInterceptor() {
    
    
                    @Override
                    public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy)
                            throws Throwable {
    
    
                        return methodProxy.invokeSuper(object, args);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable e) {
    
    
            System.out.println("**********多少次后发生了异常:  " + i);
            e.printStackTrace();
        }
    }
}

Salida

"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" ...
Error occurred during initialization of VM
MaxMetaspaceSize is too small.

El error reportado es un poco diferente. Normalmente, debería reportarse. Tal vez la versión sea diferente.
Inserte la descripción de la imagen aquí

Referencia

Metaspace 009 de OOM. Aprendizaje profundo de JVM - Metaspace

Supongo que te gusta

Origin blog.csdn.net/e891377/article/details/108771699
Recomendado
Clasificación