Java OOM 內存溢出錯誤介紹和幾種常見異常(附程序實例)

一.Java OOM介紹

在這裏插入圖片描述
OOM 全稱“Out Of Memory”,即“內存用完了”,來源於Java.lang包下的一個類:OutOfMemoryError :

  • OOM屬於error。異常Exception和錯誤Error的區別是:異常能被程序本身可以處理,錯誤是無法處理。
  • 官方解釋:Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector
  • 這個錯誤會在JVM無法爲一個對象分配足夠的內存,並且GC收集器無法回收空間時拋出

二.常見異常信息


- java.lang.StackOverflowError

棧空間溢出 ,遞歸調用卡死,注意這種Error不屬於OOM,二者是並列的

實例代碼:方法調用自身,不設置返回條件,棧逐漸加深最後報錯

public static void main(String[] args) {
        stackoverflow();
    }
    private static void stackoverflow() {
        stackoverflow();
    }


- java.lang.OutOfMemoryError:Java heap space

堆內存溢出 , 對象過大

實例代碼:

public static void main(String[] args) {

        String str = "test";
        while (true){
            str += str + new Random().nextInt(11111111);
            str.intern();
        }
    }

注意要設置JVM參數,減小堆空間heap space的容量:-Xmx10m -Xms10m



- java.lang.OutOfMemoryError:GC overhead limit exceeded

GC回收時間過長

  • 過長的定義是超過98%的時間用來做GC並且回收了而不倒2%的堆內存
  • 連續多次GC,都回收了不到2%的極端情況下才會拋出
  • 如果不拋出,那就是GC清理的一點內存很快會被再次填滿,迫使GC再次執行,這樣就惡性循環,cpu使用率一直是100%,二GC卻沒有任何成果

實例代碼

int i = 0;
List<String> list = new ArrayList<>();
try{
    while(true){
        list.add(String.valueOf(++i).intern());
    }
}catch(Throwable e){
    System.out.println("********");
    e.printStackTrace();
    throw e;
}

需設置參數 : -MaxDirectMemorySize=5m



- java.lang.OutOfMemoryError:Direct buffer memory

執行內存掛了

  • 寫NIO程序經常使用ByteBuffer來讀取或寫入數據,這是一種基於通道(Channel)與緩存區(Buffer)的I/O方式,它可以使用Native函數庫直接分配堆外內存,然後通過一個存儲在java堆裏面的DirectByteBuffer對象作爲這塊內存的引用進行操作,這樣能在一些場景中顯著提高性能,因爲避免了在java堆和native堆中來回複製數據
  • ByteBuffer.allocate(capability) 第一種方式是分配JVM堆內存,屬於GC管轄,由於需要拷貝所以速度較慢
  • ByteBuffer.alloctedDirect(capability)分配os本地內存,不屬於GC管轄,不需要拷貝,速度較快

但如果不斷分配本地內存,堆內存很少使用,那麼jvm就不需要執行GC,DirectByteBuffer對象們就不會被回收,這時候堆內存充足,但本地內存可能已經使用光了,再次嘗試分配本地內存救護i出現oom,程序崩潰


- java.lang.OutOfMemoryError:unable to create new native thread好案例

  • 應用創建了太多線程,一個應用進程創建了多個線程,超過系統承載極限
  • 你的服務器並不允許你的應用程序創建這麼多線程,linux系統默認允許單個進程可以創建的線程數是1024,超過這個數量,就會報錯

解決辦法

  • 降低應用程序創建線程的數量,分析應用給是否針對需要這麼多線程,如果不是,減到最低
  • 修改linux服務器配置


- java.lang.OutOfMemoryError:Metaspace

元空間主要存放了虛擬機加載的類的信息、常量池、靜態變量、即時編譯後的代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章