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(进程号)
2.1.2 Uso de comandos
- java -XX: + PrintFlagsInitial Ver el valor predeterminado inicial
- java -XX: + PrintFlagsInitial Ver actualizaciones de modificaciones
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
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
2.2.2 -Xmx
-Xmx es equivalente a -XX: MaxHeapSize, el tamaño máximo de espacio de almacenamiento dinámico
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
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
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
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:
Entonces, aumente el MetaspaceSize
2.3.6 -XX: + PrintGCDetails
Imprimir información de GC, el enfoque principal es la información de registro impresa
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
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
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
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
2.3.10 Resumen
Tome una foto para resumir los parámetros anteriores
Tres excepciones comunes
OOM es OutOfMemoyError. En primer lugar, está claro que OOM es un error, que es un error de memoria jvm insuficiente
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(); //不断递归调用自己
}
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];
}
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 exceeded
un 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);
}
}
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);
}
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 nativethread
razones 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.
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 #查看当前用户所能创建的最大进程数
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
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
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);
}
}
}