1. 程式人生 > 實用技巧 >JVM--你常見的jvm 異常有哪些? 程式碼演示:StackOverflowError , utOfMemoryError: Java heap space , OutOfMemoryError: GC overhead limit exceeded, Direct buffer memory, Unable_to_create_new_native_Thread, Metaspace

JVM--你常見的jvm 異常有哪些? 程式碼演示:StackOverflowError , utOfMemoryError: Java heap space , OutOfMemoryError: GC overhead limit exceeded, Direct buffer memory, Unable_to_create_new_native_Thread, Metaspace

直接上程式碼:

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();
        }

    }
}