前言
擼Java的同學,多多少少會碰到內存溢出(OOM)的場景,但造成OOM的原因卻是多種多樣。
堆溢出
這種場景最為常見,報錯信息:
原因
1、代碼中可能存在大對象分配 2、可能存在內存泄露,導致在多次GC之后,還是無法找到一塊足夠大的內存容納當前對象。
解決方法
1、檢查是否存在大對象的分配,最有可能的是大數組分配 2、通過jmap命令,把堆內存dump下來,使用mat工具分析一下,檢查是否存在內存泄露的問題 3、如果沒有找到明顯的內存泄露,使用 -Xmx 加大堆內存 4、還有一點容易被忽略,檢查是否有大量的自定義的 對象,也有可能是框架內部提供的,考慮其存在的必要性
永久代/元空間溢出
報錯信息:
原因
永久代是 虛擬機對方法區的具體實現,存放了被虛擬機加載的類信息、常量、靜態變量、JIT編譯后的代碼等。
JDK8后,元空間替換了永久代出現未結束字符串常量錯誤,重裝瀏覽器能解決嗎,元空間使用的是本地內存,還有其它細節變化:
可能原因有如下幾種:
1、在Java7之前,頻繁的錯誤使用.()方法 2、運行期間生成了大量的代理類,導致方法區被撐爆,無法卸載 3、應用長時間運行,沒有重啟
沒有重啟 JVM 進程一般發生在調試時,如下面 官網的一個 FAQ:
Why does the usage when I a web ?
That is your web has a leak.
A issue are “” leaks. They the (and the Class it ) be some are met (). They are in the heap by the JVM, and when you a new class is , which loads copy of all these . This can cause .
(*) The is that all by this be able to be gc’ed at the same time.
解決方法
因為該OOM原因比較簡單,解決方法有如下幾種:
1、檢查是否永久代空間或者元空間設置的過小 2、檢查代碼中是否存在大量的反射操作 3、dump之后通過mat檢查是否存在大量由于反射生成的代理類 4、放大招,重啟JVM
GC limit
這個異常比較的罕見,報錯信息:
原因
這個是JDK6新加的錯誤類型,一般都是堆太小導致的。Sun 官方對此的定義:超過98%的時間用來做GC并且回收了不到2%的堆內存時會拋出此異常。
解決方法
1、檢查項目中是否有大量的死循環或有使用大內存的代碼,優化代碼。
2、添加參數 -XX:- 禁用這個檢查,其實這個參數解決不了內存問題,只是把錯誤的信息延后,最終出現 java.lang.: Java heap space。
3、dump內存,檢查是否存在內存泄露,如果沒有,加大內存。
方法棧溢出
報錯信息:
原因
出現這種異常,基本上都是創建的了大量的線程導致的,以前碰到過一次,通過出來一共8000多個線程。
解決方法
1、通過 -Xss 降低的每個線程棧大小的容量 2、線程總數也受到系統空閑內存和操作系統的限制,檢查是否該系統下有此限制:
非常規溢出
下面這些OOM異常,可能大部分的同學都沒有碰到過,但還是需要了解一下
分配超大數組
報錯信息 :
這種情況一般是由于不合理的數組分配請求導致的,在為數組分配內存之前,JVM 會執行一項檢查。要分配的數組在該平臺是否可以尋址(),如果不能尋址()就會拋出這個錯誤。
解決方法就是檢查你的代碼中是否有創建超大數組的地方。
swap溢出
報錯信息 :
這種情況一般是操作系統導致的,可能的原因有:
1、swap 分區大小分配不足;
2、其他進程消耗了所有的內存。
解決方案:
1、其它服務進程可以選擇性的拆分出去 2、加大swap分區大小,或者加大機器內存大小
本地方法溢出
報錯信息 :
本地方法在運行時出現了內存分配失敗,和之前的方法棧溢出不同出現未結束字符串常量錯誤,重裝瀏覽器能解決嗎,方法棧溢出發生在 JVM 代碼層面,而本地方法溢出發生在JNI代碼或本地方法處。
這個異常出現的概率極低,只能通過操作系統本地工具進行診斷,難度有點大,還是放棄為妙。
最后
歡迎大家一起交流,喜歡文章記得關注我點個贊喲,感謝支持!