===== Directorio de artículos =====
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.Throwable
→ java.lang.Error
→ java.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 options
relleno 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;
}
}
}
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.
Referencia
Metaspace 009 de OOM. Aprendizaje profundo de JVM - Metaspace