JVM--你常見的jvm 異常有哪些? 程式碼演示:StackOverflowError , utOfMemoryError: Java heap space , OutOfMemoryError: GC overhead limit exceeded, Direct buffer memory, Unable_to_create_new_native_Thread, Metaspace
阿新 • • 發佈:2020-09-02
直接上程式碼:
public class Test001 { public static void main(String[] args) { //java.lang.StackOverflowError 棧溢位錯誤, 這個是error 不是異常,因為StackOverflowError 是Error的子類 // 棧溢位, 遞迴方法,調方法 m1(); } public static void m1(){ m1(); } @Test public void test02(){ // java.lang.OutOfMemoryError: Java heap space 堆溢位 這個是error Error的子類 // 堆溢位, 直接new 一個1G的大物件,就報異常了 ArrayList<int[]> list = new ArrayList<>(); while(true){ int[] ints = new int[1024]; list.add(ints); } //或者new 一個 大物件 //Object[] objects = new Object[1024 * 1024 * 1024]; } } class GC_OverHead_limit_demo1{ public static void main(String[] args) { //jvm 引數設定: -Xms10m -Xmx10m -XX:+PrintGCDetails // java.lang.OutOfMemoryError: GC overhead limit exceeded // 這是錯誤 // 出現的原因: 執行垃圾回收的時間佔比太大,實際工作時間太小, 預設情況下 GC話費時間超過98% ,並且垃圾回收的記憶體少於2%, 就會丟擲此錯誤 int i = 0; List<String> list = new ArrayList<>(); try { while (true){ list.add(String.valueOf(++i).intern()); } } catch (Exception e) { System.out.println(i); e.printStackTrace(); throw e; } } } class Direct_buffer_memory_demo{ private static final int BUFFER = 1024*1024*20; //20M public static void main(String[] args) { // 直接記憶體不屬於 jvm 執行時資料區的一部分 // 物件儲存的位置,不在jvm的堆中,而是在實體記憶體中(直接記憶體中,為記憶體的1/4), 這樣直接記憶體中的物件不停增加,直到滿了,而此時jvm 的 gc並不會執行,所以報這個錯誤 // java.lang.OutOfMemoryError: Direct buffer memory // 怎樣檢視直接記憶體大小 sun.misc.VM.maxDirectMemory() /1024/1024 單位 m // jvm 引數:設定堆最大為10m, -Xms10m -Xmx10m -XX:+PrintGCDetails 可以設定直接記憶體,如果不設定 和堆空間最大值相同 System.out.println(VM.maxDirectMemory() / 1024 / 1024);// 直接記憶體大小為 9m ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10 * 1024 * 1024);//這裡直接放10m 的快取 } } class Unable_to_create_new_native_Thread_demo{ public static void main(String[] args) throws InterruptedException { // 這個是高併發情況下 容易爆出的生產上的錯誤 // java.lang.OutOfMemoryError: Unable_to_create_new_native_Thread // 一個應用程序裡 建立了過個執行緒,直接撐爆最大上限, linux伺服器預設普通使用者一個程序建立執行緒上限為1024, 如果是root使用者則無上限 // 解決方案: 遇到這個錯誤,分析程式是否需要這麼多執行緒,改程式碼, 或者修改伺服器配置,增加建立執行緒上限 // https://www.jianshu.com/p/103589cea5f5 // https://blog.csdn.net/east4ming/article/details/80179670 //這裡模擬一個 main執行緒下 建立多個執行緒 AtomicInteger count = new AtomicInteger(); while(true){ new Thread(()->{ try { count.getAndIncrement(); System.out.println(count.get()); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } //這個在win系統下 並沒有測出錯誤結果, 在linux系統下 930多個就報錯誤了 } } class MetaSpace_demo1{ static class OOM_Test{ //靜態內部類 } public static void main(String[] args) { // 1.8之後,元空間取代了 永久代, 且元空間不在 jvm的 執行時資料區,而是使用的本地記憶體 // jvm引數: -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=10m // 執行結果: 396 時候就報錯誤了; java.lang.OutOfMemoryError: Metaspace /** * 元空間 存放的資訊: * 1: 虛擬機器載入的類資訊 * 2: 常量池 * 3: 靜態變數 * 4: 即使編譯後的程式碼 * * 所以: 不停地建立 靜態類,存放到元空間,直到撐爆,報異常 */ int i = 0; try { while(true){ i++; //這裡使用 cglib 生成代理類, 這個類是靜態的,所以建立後放在元空間 //1, 建立工具類 Enhancer enhancer = new Enhancer(); //2, 設定父類 enhancer.setSuperclass(OOM_Test.class); enhancer.setUseCache(false);//不使用快取 //3, 設定回撥函式 enhancer.setCallback(new MethodInterceptor(){ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o,args); } }); //4, 建立代理物件 Object o = enhancer.create(); } } catch (Exception e) { System.out.println(i); e.printStackTrace(); } } }