想办法让Jvm的各个分区OOM ### 堆内存 堆内存溢出主要是一直创建对象,但是又不能被GC回收(可达性分析,GC Root和对象之间有可达路径)就会溢出了。 参数:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError ``` byte[] a = new byte[21 * 1024 * 1024]; ``` 加上`HeapDumpOnOutOfMemoryError` 可以dump出日志,便于后续分析OOM的问题所在 ### 栈内存溢出 虚拟机栈里有个局部变量表,通过不断创建局部变量,可以让它爆掉 (这里没成功OOM,不懂是Jvm的原因还是什么) 参数: -Xss1m -XX:+HeapDumpOnOutOfMemoryError ``` java public void StackOOM() { while (true) { Thread thread = new Thread(this::job); thread.start(); } } private void job() { while (true) { } } ``` ### 方法区溢出 方法区用于存放类的信息,所以想要溢出方法区,只要动态地生成大量的类就可以了。比较简单地生成类的方法是通过使用Cglib生成。所以说 有使用Cglib的项目是有可能出现方法区溢出异常的,比如Spring的Aop,如果大量的增强类,会产生很多的类,方法区的大小不够就会产生异常。 如果使用`-XX:PermSize=1M -XX:MaxPermSize=1M`,要确保jvm版本低于8,因为Java1.8移除了永久代,类信息放在了Meta Space。 控制Meta space用 `-XX:MetaspaceSize` 和 `-XX:MaxMetaspaceSize` 参数:-XX:MaxMetaspaceSize=10m -XX:MetaspaceSize=10m -Xmx20m -Xms10m ``` java while (true){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TestMain.class); enhancer.setUseCache(false); enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects)); enhancer.create(); } ``` > Exception in thread "main" java.lang.OutOfMemoryError: Metaspace ### 直接内存溢出 直接内存溢出通常出现在Nio出现的地方,比如Netty。可以通过unsafe方法直接请求系统内存来模拟直接内存溢出。 参数: -XX:MaxDirectMemorySize=10M -XX:+HeapDumpOnOutOfMemoryError ``` java Field field = Unsafe.class.getDeclaredFields()[0]; field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); while (true) { unsafe.allocateMemory(1 * 1024 * 1024); } ``` > Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method)