1、java.lang.StackOverflowError
- 在一個函數中調用自己就會產生這樣的錯誤(棧溢出)
- 發生區域:java虛擬機棧或本地方法棧
public class StackOverFlowErrorDemo { public static void main(String[] args) { stackOverFlowError(); } public static void stackOverFlowError(){ stackOverFlowError(); } }
2、java.lang.OutOfMemoryError: Java heap space
- new 一個很大對象
- 發生區域:java堆
/** * -Xms10m -Xmx10m */ public class JavaHeapSpaceDemo { static class OOMObject{ } public static void main(String[] args) { List<OOMObject> list = new ArrayList<>(); while (true){ list.add(new OOMObject()); } } }
3、java.lang.OutOfMemoryError: GC overhead limit exceeded
- GC回收時間過長,超過98%的時間用來做GC,並且回收了不到2%的堆內存
/** * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m */ public class GCoverheadDemo { public static void main(String[] args) { int i = 0; List<String> list = new ArrayList<>(); while (true) { list.add(String.valueOf(++i).intern()); } } }
4、java.lang.OutOfMemoryError: Direct buffer memory
原因:直接內存不足
寫NIO程序經常使用ByteBuffer來讀取或寫入數據,這是一種基於通道與緩沖區的I/O方式
ByteBuffer.allocate() 分配JVM堆內存,屬於GC管轄范圍,需要拷貝所以速度相對較慢
ByteBuffer.allocateDirect() 分配操作系統本地內存,不屬於GC管轄范圍,不需要內存拷貝所以速度相對較快
/** * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m */ public class DirectBufferMemoryDemo { public static void main(String[] args) throws InterruptedException { System.out.println("maxDirectMemory : " + sun.misc.VM.maxDirectMemory() / 1024 / 1024 + "MB"); TimeUnit.SECONDS.sleep(1); ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024); } }
5、java.lang.OutOfMemoryError : unable to create new native thread
- 一個應用進程創建了多個線程,超過系統承載極限,Linux默認允許單個進程可以創建的線程數1024
/** * 一個應用進程創建了多個線程,超過系統承載極限,Linux默認是1024 */ public class UnableCreateNewThreadDemo { public static void main(String[] args) { for (int i = 0; ; i++) { new Thread(() -> { try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } }, String.valueOf(i)).start(); } } }
linux系統下:
ulimit -u --查看線程上限 cat /etc/security/limits.d/20-nproc.conf
6、java.lang.OutOfMemoryError: Metaspace
java8使用Metaspace代替永久代,與永久代最大的區別是:元空間並不在虛擬機內存中,而是使用本地內存。
永久代(java8使用Metaspace)存放的信息:
- 虛擬機加載的類信息
- 常量池
- 靜態變量
- 即時編譯后的代碼
/** * 不斷生成類往元空間推,類占據的空間總是會超過Metaspace的大小 * -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m */ public class MetaspaceOOMDemo { static class OOMTest { } public static void main(String[] args) { int i = 0; //模擬計數多少次后發生了異常 try { while (true) { i++; 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(i + "次后發送了異常"); e.printStackTrace(); } } }