JVM (9): configuración de parámetros comunes de JVM y excepciones de OOM

Uno, tipo de parámetro JVM

Hay 3 tipos de parámetros de JVM:

  • Parámetro estándar
  • Parámetro X
  • Parámetro XX

1.1 Parámetros estándar

Los parámetros estándar permanecen básicamente sin cambios en cada versión de la JVM. Relativamente estable, por ejemplo:

  • -ayuda
  • -servidor -cliente
  • -versión -showversion
  • -cp -classpath

1.2 X parámetros

  • Interpretación y ejecución de Xint
  • -Xcomp: compila el código local la primera vez que lo usa
  • -Xmixed: modo mixto, JVM decide si compila el código local por sí mismo

1.3 XX parámetros

El parámetro xx es el parámetro principal que debemos configurar para el ajuste. El parámetro XX se divide en dos categorías: tipo booleano y tipo de configuración kv

  • Tipo booleano: Formato: -XX: [±] significa habilitar o deshabilitar el atributo de nombre. El signo + indica que el parámetro está habilitado y el signo-indica que el parámetro está inhabilitado.

  • Parámetros de tipo de par clave-valor de KV

Formato: -XX: = indica que el valor del atributo de nombre es valor, principalmente en forma de clave y valor.

2. Parámetros comunes

2.1 Ver valores predeterminados

2.1.1 jinfo

La función de jinfo es ver y ajustar varios parámetros de la máquina virtual en tiempo real. Por ejemplo: necesita ver el tamaño del metaespacio en el jvm

jinfo -flag MetaspaceSize 15264(进程号)

imagen-20201225192147441

2.1.2 Uso de comandos
  • java -XX: + PrintFlagsInitial Ver el valor predeterminado inicial

imagen-20201225192335854

  • java -XX: + PrintFlagsInitial Ver actualizaciones de modificaciones

imagen-20201225192816621

Mirando la salida, encontrará que algunos de ellos son: =, estos son los valores modificados

  • = No ha sido modificado
  • : = Modificado

2.2 Parámetros de uso común de JVM

2.2.1 -Xms

-Xms es equivalente a -XX: InitialHeapSize, el tamaño del espacio de pila inicializado

imagen-20201225195339698

El tamaño de espacio de pila predeterminado es 1/64 de la memoria de la computadora, mi computadora tiene 20 g de memoria, por lo que el tamaño de espacio de pila inicial es de 320 MB

Ejemplo de uso: -Xms10m

imagen-20201225195831573

2.2.2 -Xmx

-Xmx es equivalente a -XX: MaxHeapSize, el tamaño máximo de espacio de almacenamiento dinámico

imagen-20201225200241874

El tamaño de espacio de pila máximo predeterminado es 1/4 de la memoria de la computadora, por lo que el tamaño de espacio de pila máximo es 5120mb

Ejemplo de uso: -Xmx10m

imagen-20201225200607096

2.2.3 -Xss

Establezca el tamaño de la memoria del montón, equivalente a -XX: ThreadStackSize

El valor predeterminado es generalmente 512 k ~ 1024 k

imagen-20201226094317425

Aquí -XX: ThreadStackSize = 0 es 0, no es que el tamaño de memoria de la pila de la máquina virtual sea 0, sino el valor predeterminado de jvm

Ejemplo de uso: -Xss1024k

imagen-20201226094544778

2.3.4 -Xmn

Establezca el tamaño de la generación joven, el tamaño de la generación joven es generalmente 1/3 del montón, y este parámetro generalmente no cambia

2.3.5 -XX: MetaspaceSize

-XX: MetaspaceSize es para establecer el tamaño del metaespacio, el metaespacio no está en la máquina virtual, pero se usa la memoria local, por lo que, por defecto, el tamaño del metaespacio está limitado por la memoria local

Ver el valor inicial del metaespacio:

imagen-20201226095643692

Entonces, aumente el MetaspaceSize

2.3.6 -XX: + PrintGCDetails

Imprimir información de GC, el enfoque principal es la información de registro impresa

-XX_ + PrintGCDetalla la información de impresiónimagen-20201227123936029

La información de registro después de la impresión de GC se divide principalmente por ->, el frente está antes del GC, la parte posterior está después del GC y el tamaño total entre paréntesis

2.3.7 -XX: SurvivorRatio

Establece la proporción entre el área de Edén y el área de Superviviente (desde el área de supervivencia o hasta el área de supervivencia) en el Cenozoico. El valor predeterminado es 8

imagen-20201227130739072

Utilice XX: SurvivorRatio para establecer esta proporción

2.3.8 -XX: NewRatio

Establezca la relación entre la generación joven y la generación anterior, el valor predeterminado es 2

imagen-20201227131113791

Utilice -XX: NewRatio para establecer este tamaño de relación

2.3.9 -XX: MaxTenuringThreshold

Controle cuántas veces la generación joven debe pasar por la promoción de GC hasta el umbral máximo en la generación anterior, el valor predeterminado es 15

imagen-20201227131253986

Tenga en cuenta que la configuración de este valor debe estar entre 0-15. La siguiente imagen muestra el error que quiero establecer en 20 y luego informar un error. La razón es que el valor máximo para controlar este objeto para ser promovido a la vejez es en el encabezado del objeto, y se usan 2 Bits, por lo que el valor máximo es 15

imagen-20201227131403346

2.3.10 Resumen

Tome una foto para resumir los parámetros anteriores

Parámetros comunes de JVM

Tres excepciones comunes

OOM es OutOfMemoyError. En primer lugar, está claro que OOM es un error, que es un error de memoria jvm insuficiente

imagen-20201229203844943

En la especificación de la máquina virtual Java, se estipula claramente que todas las áreas de datos en tiempo de ejecución que no sean el contador del programa pueden emitir excepciones OOM (por supuesto, estamos acostumbrados a llamarlas verbalmente excepciones)

3.1 StackOverflowError

StackOverflowError es una excepción de desbordamiento de pila. Si la profundidad de la pila solicitada por el hilo es mayor que la profundidad permitida por la máquina virtual, se lanzará un StackOverflowError, por ejemplo:

public static void main(String[] args) {
    
    
    test();
}
public static void test(){
    
    
    test();	//不断递归调用自己
}

imagen-20201229204642034

3.2 OOM: espacio de almacenamiento dinámico de Java

/**
     * -Xms5m -Xmx5m
     * @param args
     */
public static void main(String[] args) {
    
    
    Byte[] bytes = new Byte[10 * 1024 * 1024];
}

imagen-20201229204947624

La solución es ajustar el tamaño del montón.

3.3 OOM: se excedió el límite de sobrecarga del GC

Cuando el proceso de Java tarda más del 98% del tiempo en realizar la GC, pero solo recupera menos del 2% de la memoria, y la acción se repite cinco veces seguidas, arrojará java.lang.OutOfMemoryError:GC overhead limit exceededun error. En pocas palabras, la aplicación básicamente ha agotado toda la memoria disponible y el GC no puede recuperarla. Esto debería generar una excepción. Si no lanza una excepción, hará que el 2% de la memoria limpiada por el GC se llene de inmediato, lo que hará que el GC se ejecute nuevamente y luego se vuelva a llenar, lo que lleva a un círculo vicioso

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

}

imagen-20201229210310101

3.4 OOM: memoria intermedia directa

Java permite que las aplicaciones accedan directamente a la memoria fuera del montón a través de Direct ByteBuffer, y muchos programas de alto rendimiento implementan E / S de alta velocidad a través de Direct ByteBuffer combinado con Memory Mapped File. El programa NIO de Javad usa ByteBuffer para leer o escribir datos. ByteBuffer tiene dos formas:

  • asignar: asigna memoria de pila JVM, que pertenece al rango de recuperación de GC, pero la velocidad es lenta debido a la copia de la memoria local
  • allocateDirect: asigna directamente memoria fuera del montón, es decir, memoria local, con una velocidad de transmisión más rápida
/**
     * -XX:MaxDirectMemorySize=5m
     * @param args
     */
public static void main(String[] args) {
    
    
    ByteBuffer.allocateDirect(6 * 1024 * 1024);
}

imagen-20201229211855036

3.5 OOM: No se puede crear un nuevo hilo nativo

JVM solicita al sistema operativo que cree un subproceso nativo si falla, lo descartará.Las Unable to create new nativethreadrazones comunes incluyen los siguientes tipos:

1. El número de subprocesos excede el límite ulimit del número máximo de subprocesos del sistema operativo;

2. El número de subprocesos excede kernel.pid_max (solo se puede reiniciar);

3. Memoria nativa insuficiente;

public class UnableCreateNewThreadDemo {
    
    
    public static void main(String[] args) {
    
    
        int i = 0;
        try {
    
    
            for (;;i++) {
    
    
                new Thread(() -> {
    
    
                    //防止进程醒来
                    try {
    
     TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {
    
    e.printStackTrace();}
                }).start();
            }
        }catch (Throwable e){
    
    
            e.printStackTrace();
        }finally {
    
    
            System.out.println(i);
        }
    }
}

Ejecute el programa java anterior en Centos7. Nota: Necesita utilizar un usuario normal para ejecutar este programa. El uso de root puede hacer que el proceso se cree todo el tiempo y hacer que la máquina se atasque.

imagen-20201230212644363

Se encontró que se crearon 4085 procesos y se informó de la excepción No se pudo crear un nuevo subproceso nativo.

Hay dos soluciones a los problemas anteriores:

  • Incrementar la cantidad máxima de procesos permitidos por el sistema operativo, tome Centos7 como ejemplo
[test@hadoop101 ~]$ ulimit -u	#查看当前用户所能创建的最大进程数

imagen-20201230213004120

Se puede encontrar que, de hecho, es algo diferente del 4085 anterior, y habrá algunos procesos demonio cuando se esté ejecutando el programa java.

El número máximo de procesos que pueden crear los usuarios normales se puede aumentar modificando el archivo de configuración /etc/security/limits.d/20-nproc.conf

imagen-20201230214510271

También se puede ver de lo anterior que el número máximo de procesos que tienen los usuarios ordinarios es 4096, luego este valor se puede modificar para aumentar el número de procesos.

  • El segundo método es reducir los procesos innecesarios.

3.6 OOM: Metaspace

El metaespacio almacena la información estructural de la clase. El metaespacio no está en la JVM, sino en la memoria local, pero el tamaño predeterminado del metaespacio es solo cercano a 21mb

imagen-20201230220036713

Por lo tanto, puede haber una situación OOM, mire el siguiente código:

public class MetaspaceDemo extends ClassLoader{
    
    
    /**
     *jdk1.8 环境配置如下参数
     * -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
     * @param args
     */
    public static void main(String[] args) {
    
    
        int j = 0;
        try {
    
    
            MetaspaceDemo test = new MetaspaceDemo();
            for (int i = 0; i < 10000; i++) {
    
    
                //创建ClassWriter对象,用于生成类的二进制字节码
                ClassWriter classWriter = new ClassWriter(0);
                //指明版本号,修饰符,类名,包名,父类,接口
                classWriter.visit(Opcodes.V1_6, 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);
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/weixin_44706647/article/details/115193964
Recomendado
Clasificación