Java內存溢出OutOfMemoryError的產生與排查

在java的虛擬機異常中,有兩個異常是大家比較關心的,一個是StackOverflowError,另一個是OutOfMemoryError。今天我們就來看看OutOfMemoryError是怎麼產生的,以及如何去排查這個異常。

概念

要了解什麼是OutOfMemoryError,我們可以直接看一下OutOfMemoryError的源碼,在類上的英文註釋很好的闡述了什麼是OutOfMemoryError,翻譯過來的意思是,由於內存不足,虛擬機沒有可分配的內存了,垃圾回收器也不能釋放更多的內存。在生產環境中,由於訪問量過大,把內存吃滿,會出現OutOfMemoryError的異常,小夥伴們如果沒有經驗的話,往往束手無策,到底是真的內存不夠用了,還是自己的程序有問題,也不知道如何去排查這樣的異常。

模擬OutOfMemoryError

在這裏,我們寫一段程序,來模擬一下OutOfMemoryError如何產生,我們創建一個List對象,然後向裡邊不停的添加1M的Byte,如下;

 public static void main(String[] args) {
     List<Byte[]> list = new ArrayList<>();
     int i = 0;
     try {
         while (true) {
             list.add(new Byte[1024 * 1024]);
             i++;
         }
     } catch (Throwable e) {
         e.printStackTrace();
         System.out.println("執行了"+i+"次");
     }
 }
  • 我們寫了一個while(true)循環,每次都add一個1M的字節對象,1024*1024正好1M。
  • 我們用i的值記錄總共執行了幾次。
  • 如果這樣不停的執行下去,不管你有多大的內存,都會被吃光的。

我們為了讓程序運行時,快速的拋出OutOfMemoryError異常,可以在java的啟動命令行增加啟動參數,設置堆內存的初始值和最大值。這兩個值在生產環境下,通常也是要配置的哦,要充分利用機器的內存嘛,如果不配置就會使用默認值。到時候由於內存不足向老闆申請機器,可別挨罵哦~

那這兩個參數怎麼去加呢?

  • -Xms ,-Xms設置初始堆內存的大小
  • -Xmx, -Xmx設置最大堆內存的大小

通常情況下,這兩個值設置成一樣就可以了,總之,我們設置了堆內存的大小。我們在IDEA的啟動配置中,統一設置堆內存為80M,如下;

好了~~我們運行一下,看看會不會拋出OutOfMemoryError異常吧

java.lang.OutOfMemoryError: Java heap space
	at com.diancan.JavaOOMDemo.main(JavaOOMDemo.java:14)
執行了14次

執行了14次,拋出了OutOfMemoryError異常。但是,如果拋出這樣一個異常,我們怎麼去排查呢?就這一行日誌也看不出什麼來啊。

排查

說到排查,如果我們能夠拿到異常時的內存快照,然後通過一些工具就可以了進行內存的分析了。那麼我們怎麼去拿到內存溢出時的快照呢?其實,JDK也為我們提供了這樣的命令參數,我們來看一下吧,

  • -XX:+HeapDumpOnOutOfMemoryError,從字面就可以很容易的理解,在發生OutOfMemoryError異常時,進行堆的Dump,這樣就可以獲取異常時的內存快照了。
  • -XX:HeapDumpPath=D:\heap-dump\ ,這個也很好理解,就是配置HeapDump的路徑,方便我們管理,這裏我們配置為D:\heap-dump,當然你也可以根據自己的需要,定義為其他的目錄。

注意,HeapDumpPath的目錄一定要手動創建好,如果沒有這個目錄,Dump會失敗的。

IDEA中的配置,如圖:

我們再運行一下程序,看看是什麼樣子,

java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:\heap-dump\java_pid24312.hprof ...
Heap dump file created [123468648 bytes in 0.141 secs]
java.lang.OutOfMemoryError: Java heap space
	at com.diancan.JavaOOMDemo.main(JavaOOMDemo.java:14)
執行了14次

我們發現日誌上面多了點東西,創建了一個文件,在D:\heap-dump\java_pid24312.hprof。這個文件就是我們的內存快照。那麼問題來了,我們如何查看這個文件呢?直接打開是不行的,用寫字板等也是不行的,那怎麼辦?其實也沒那麼複雜,使用JDK自帶的jvisualvm就可以查看。

這裏邊有個小坑,如果大家用JDK8,可以在JDK的bin目錄下找到jvisualvm.exe,但是如果你使用的是JDK8以上的版本,就本示例中,使用的是JDK11,在bin目錄下是找不到jvisualvm.exe的。大家可以去visualvm的主頁下載。

我們啟動visualvm,進入到如下的頁面,

然後,點擊左上角的加載快照按鈕,然後選擇剛才我們Dump的文件,

我們重點看一下右側中間的部分,

類的實例大小排序,可以看到,我們的Byte佔了96.5%。詳細的信息,我們可以點進去看,包括變量里存的內容,這樣我們就可以很快的定位到內存溢出的位置,並且可以判斷是真的內存不夠了,還是我們的代碼出了問題。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準