一、引言

从事java开发的小伙伴在平时的开发工作中,应该会遇见各式各样的异样和谬误,在理论工作中积攒的异样或者谬误越多,趟过的坑越多,就会使咱们编码更加的强壮,就会本能地避开很多重大的坑。以下介绍几个Java虚拟机常见内存溢出谬误。以此警示,防止生产血案。

二、模仿Java虚拟机常见内存溢出谬误

1、内存溢出之栈溢出谬误

package com.jayway.oom;    /**   * 栈溢出谬误   * 虚拟机参数:-Xms10m -Xmx10m   * 抛出异样:Exception in thread "main" java.lang.StackOverflowError   */ public class StackOverflowErrorDemo {     public static void main(String[] args) {      stackOverflowError();   }     private static void stackOverflowError() {      stackOverflowError();   }    }

2、内存溢出之堆溢出谬误

package com.jayway.oom;    import java.util.Random;    /**   * 堆溢出谬误   * 虚拟机参数:-Xmx10m -Xms10m * 抛出异样:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space   */ public class JavaHeapSpaceErrorDemo {     public static void main(String[] args) {      String temp = "java";      //一直地在堆中开拓空间,创建对象,撑爆堆内存    while (true) {          temp += temp + new Random().nextInt(111111111) + new Random().nextInt(222222222);          temp.intern();      }   }  }

3、内存溢出之GC超过执行限度谬误

package com.jayway.oom;    import java.util.ArrayList;  import java.util.List;    /**   * GC超过执行限度谬误   * 虚拟机参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m   * * 抛出异样:Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded   * * 导致起因:GC回收工夫过长会抛出OutOfMemoryError,何为过长,即超过98%的cpu工夫用来做GC垃圾回收   * 然而回收成果甚微,仅仅只有2%的CPU工夫用来用户程序的工作,这种状态是很蹩脚的,程序在一直地GC   * 造成恶性循环,CPU的使用率始终是满负荷的,正经活却没有干,这种状况虚拟机只好抛出谬误来终止程序的执行   *   * 一直地Full GC,事倍功微   * [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7161K(7168K)] 9215K->9209K(9728K), [Metaspace: 3529K->3529K(1056768K)], 0.0291829 secs] [Times: user=0.08 sys=0.02, real=0.03 secs]   */ public class GCOverheadErrorDemo {        public static void main(String[] args) {          int i = 0;          List<String> list = new ArrayList<>();          try {              while (true) {              list.add(String.valueOf(++i).intern());              }          } catch (Throwable e) {              System.out.println("*****************i:" + i);              e.printStackTrace();              throw e;          }      }  }

4、内存溢出之间接内存溢出谬误

package com.jayway.oom;    import java.nio.ByteBuffer;    /**   * 间接内存溢出谬误   * 抛出异样:Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory   * * 配置虚拟机参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m   * * 导致起因:通常NIO程序常常应用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的IO形式,   * 它能够应用Native函数库间接调配堆外内存,而后通过一个存储在java堆外面的DirectByteBuffer对象作为这块内存的援用,   * 这样能子一些场景中显著进步性能,因为防止了在Java堆和Native内存中来回复制数据。   *   * ByteBuffer.allocate(capability):调配JVM堆内存,数据GC的管辖范畴,因为须要拷贝所以速度绝对较慢   *   * ByteBuffer.allocate(capability):调配OS本地内存,不属于GC管辖范畴,因为不须要内存拷贝,所以速度绝对较快。   *   * 然而如果一直调配本地内存,堆内存很少应用,那么JVM就不须要执行GC,DirectByteBuffer对象就不会被回收,此时如果持续调配堆外内存,   * 可能堆外内存曾经被耗光了无奈持续调配,此时程序就会抛出OutOfMemoryError,间接解体。   *   */ public class DirectBufferMemoryErrorDemo {        public static void main(String[] args) {          //默认JVM配置的最大间接内存是总物理内存的四分之一          long maxDirectMemory = sun.misc.VM.maxDirectMemory() / 1024 / 1024;          System.out.println("配置的maxDirectMemory:" + maxDirectMemory + "MB");            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);      }    }

5、内存溢出之无奈创立新的本地线程

package com.jayway.oom;    /**   * 内存溢出之无奈创立新的本地线程   * 抛出异样:java.lang.OutOfMemoryError: unable to create new native thread   * * 形容:   * 高并发申请服务器时,经常出现java.lang.OutOfMemoryError: unable to create new native thread   *      native thread异样与对应的平台无关   *   * 导致起因:   *      1、应用程序创立了太多线程了,一个利用过程创立的线程数超过零碎承载极限。   *      2、操作系统并不容许你的利用过程创立这么多的线程,linux零碎默认容许单个过程能够创立的线程数是1024个   *   * 解决办法:   *      1、想方法升高利用过程创立的线程数量,   *      2、如果应用程序的确须要这么多线程,超过了linux零碎的默认1024个限度,能够通过批改linux服务器配置,进步这个阈值。   *   */ public class UnableCreateNativeThreadErrorDemo {        public static void main(String[] args) {          for (int i = 0; true; i++) {              System.out.println("***************i:" + i);                //一直得创立新线程,直到超过操作系统容许利用过程创立线程的极限              new Thread(() -> {                  try {                      Thread.sleep(Integer.MAX_VALUE);                  } catch (InterruptedException e) {                      e.printStackTrace();                  }              }).start();          }      }  }

6、内存溢出之元空间溢出谬误

package com.jayway.oom;    import org.springframework.cglib.proxy.Enhancer;  import org.springframework.cglib.proxy.MethodInterceptor;  import org.springframework.cglib.proxy.MethodProxy;    import java.lang.reflect.Method;    /**   * 元空间溢出谬误   * 抛出异样:java.lang.OutOfMemoryError: Metaspace   * * 设置虚拟机参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m   * * 形容:Java8及当前的版本应用Metaspace来代替了永恒代。metaspace是办法区在HotSpot中的实现,它与长久代最大的区别在于   *      Metaspace并不在虚拟机内存中而是在本地内存中。   *   * 元空间存储了以下信息:   *      1、虚拟机加载的类信息   *      2、常量池   *      3、动态变量   *      4、即时编译后的代码   *   */ public class MetaspaceErrorDemo {        static class OOMTest {      }        public static void main(String[] args) {          int count = 0;            try {          //cglib一直创立类,模仿Metaspace空间溢出,咱们一直生成类往元空间中灌,超过元空间大小后就会抛出元空间移除的谬误              while (true) {                  count++;                  Enhancer enhancer = new Enhancer();                  enhancer.setSuperclass(OOMTest.class);                  enhancer.setUseCache(false);                  enhancer.setCallback(new MethodInterceptor() {                      @Override                      public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {                          return methodProxy.invokeSuper(o, args);                      }                  });                  enhancer.create();              }          } catch (Throwable e) {              System.out.println("************多少次后产生了异样:" + count);              e.printStackTrace();          }      }  }