在java的虛擬機異常中,有兩個異常是你們比較關心的,一個是StackOverflowError,另外一個是OutOfMemoryError。今天咱們就來看看OutOfMemoryError是怎麼產生的,以及如何去排查這個異常。java
要了解什麼是OutOfMemoryError,咱們能夠直接看一下OutOfMemoryError的源碼,在類上的英文註釋很好的闡述了什麼是OutOfMemoryError,翻譯過來的意思是,因爲內存不足,虛擬機沒有可分配的內存了,垃圾回收器也不能釋放更多的內存。在生產環境中,因爲訪問量過大,把內存吃滿,會出現OutOfMemoryError的異常,小夥伴們若是沒有經驗的話,每每一籌莫展,究竟是真的內存不夠用了,仍是本身的程序有問題,也不知道如何去排查這樣的異常。git
在這裏,咱們寫一段程序,來模擬一下OutOfMemoryError如何產生,咱們建立一個List對象,而後向裏邊不停的添加1M的Byte,以下;github
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+"次"); } }
咱們爲了讓程序運行時,快速的拋出OutOfMemoryError異常,能夠在java的啓動命令行增長啓動參數,設置堆內存的初始值和最大值。這兩個值在生產環境下,一般也是要配置的哦,要充分利用機器的內存嘛,若是不配置就會使用默認值。到時候因爲內存不足向老闆申請機器,可別捱罵哦~shell
那這兩個參數怎麼去加呢?工具
一般狀況下,這兩個值設置成同樣就能夠了,總之,咱們設置了堆內存的大小。咱們在IDEA的啓動配置中,統一設置堆內存爲80M,以下;spa
好了~~咱們運行一下,看看會不會拋出OutOfMemoryError異常吧命令行
java.lang.OutOfMemoryError: Java heap space at com.diancan.JavaOOMDemo.main(JavaOOMDemo.java:14) 執行了14次
執行了14次,拋出了OutOfMemoryError異常。可是,若是拋出這樣一個異常,咱們怎麼去排查呢?就這一行日誌也看不出什麼來啊。翻譯
說到排查,若是咱們可以拿到異常時的內存快照,而後經過一些工具就能夠了進行內存的分析了。那麼咱們怎麼去拿到內存溢出時的快照呢?其實,JDK也爲咱們提供了這樣的命令參數,咱們來看一下吧,日誌
注意,HeapDumpPath的目錄必定要手動建立好,若是沒有這個目錄,Dump會失敗的。code
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%。詳細的信息,咱們能夠點進去看,包括變量裏存的內容,這樣咱們就能夠很快的定位到內存溢出的位置,而且能夠判斷是真的內存不夠了,仍是咱們的代碼出了問題。