前言
撸Java的同學,多多少少會碰到記憶體溢出(OOM)的場景,但造成OOM的原因卻是多種多樣。
堆溢出
這種場景最為常見,報錯資訊:
java.lang.OutOfMemoryError: Java heap space
原因
1、代碼中可能存在大對象配置設定
2、可能存在記憶體洩露,導緻在多次GC之後,還是無法找到一塊足夠大的記憶體容納目前對象。
解決方法
1、檢查是否存在大對象的配置設定,最有可能的是大數組配置設定
2、通過jmap指令,把堆記憶體dump下來,使用mat工具分析一下,檢查是否存在記憶體洩露的問題
3、如果沒有找到明顯的記憶體洩露,使用 -Xmx 加大堆記憶體
4、還有一點容易被忽略,檢查是否有大量的自定義的 Finalizable 對象,也有可能是架構内部提供的,考慮其存在的必要性
永久代/元空間溢出
報錯資訊:
java.lang.OutOfMemoryError: PermGen spacejava.lang.OutOfMemoryError: Metaspace
永久代是 HotSot 虛拟機對方法區的具體實作,存放了被虛拟機加載的類資訊、常量、靜态變量、JIT編譯後的代碼等。
JDK8後,元空間替換了永久代,元空間使用的是本地記憶體,還有其它細節變化:
字元串常量由永久代轉移到堆中
和永久代相關的JVM參數已移除
可能原因有如下幾種:
1、在Java7之前,頻繁的錯誤使用String.intern()方法
2、運作期間生成了大量的代理類,導緻方法區被撐爆,無法解除安裝
3、應用長時間運作,沒有重新開機
沒有重新開機 JVM 程序一般發生在調試時,如下面 tomcat 官網的一個 FAQ:
Why does the memory usage increase when I redeploy a web application? That is because your web application has a memory leak. A common issue are “PermGen” memory leaks. They happen because the Classloader (and the Class objects it loaded) cannot be recycled unless some requirements are met (). They are stored in the permanent heap generation by the JVM, and when you redeploy a new class loader is created, which loads another copy of all these classes. This can cause OufOfMemoryErrors eventually. (*) The requirement is that all classes loaded by this classloader should be able to be gc’ed at the same time.
因為該OOM原因比較簡單,解決方法有如下幾種:
1、檢查是否永久代空間或者元空間設定的過小
2、檢查代碼中是否存在大量的反射操作
3、dump之後通過mat檢查是否存在大量由于反射生成的代理類
4、放大招,重新開機JVM
歡迎大家關注我的公種浩【程式員追風】,文章都會在裡面更新,整理的資料也會放在裡面。

GC overhead limit exceeded
這個異常比較的罕見,報錯資訊:
java.lang.OutOfMemoryError:GC overhead limit exceeded
這個是JDK6新加的錯誤類型,一般都是堆太小導緻的。Sun 官方對此的定義:超過98%的時間用來做GC并且回收了不到2%的堆記憶體時會抛出此異常。
1、檢查項目中是否有大量的死循環或有使用大記憶體的代碼,優化代碼。
2、添加參數 -XX:-UseGCOverheadLimit 禁用這個檢查,其實這個參數解決不了記憶體問題,隻是把錯誤的資訊延後,最終出現 java.lang.OutOfMemoryError: Java heap space。
3、dump記憶體,檢查是否存在記憶體洩露,如果沒有,加大記憶體。
方法棧溢出
java.lang.OutOfMemoryError : unable to create new native Thread
出現這種異常,基本上都是建立的了大量的線程導緻的,以前碰到過一次,通過jstack出來一共8000多個線程。
1、通過 -Xss 降低的每個線程棧大小的容量 2、線程總數也受到系統空閑記憶體和作業系統的限制,檢查是否該系統下有此限制:
/proc/sys/kernel/pid_max
/proc/sys/kernel/thread-max
maxuserprocess(ulimit -u)
/proc/sys/vm/maxmapcount
非正常溢出
下面這些OOM異常,可能大部分的同學都沒有碰到過,但還是需要了解一下
配置設定超大數組
報錯資訊 :
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
這種情況一般是由于不合理的數組配置設定請求導緻的,在為數組配置設定記憶體之前,JVM 會執行一項檢查。要配置設定的數組在該平台是否可以尋址(addressable),如果不能尋址(addressable)就會抛出這個錯誤。
解決方法就是檢查你的代碼中是否有建立超大數組的地方。
swap溢出
java.lang.OutOfMemoryError: Out of swap space
這種情況一般是作業系統導緻的,可能的原因有:
1、swap 分區大小配置設定不足;
2、其他程序消耗了所有的記憶體。
解決方案:
1、其它服務程序可以選擇性的拆分出去
2、加大swap分區大小,或者加大機器記憶體大小
本地方法溢出
java.lang.OutOfMemoryError: stack_trace_with_native_method
本地方法在運作時出現了記憶體配置設定失敗,和之前的方法棧溢出不同,方法棧溢出發生在 JVM 代碼層面,而本地方法溢出發生在JNI代碼或本地方法處。
這個異常出現的機率極低,隻能通過作業系統本地工具進行診斷,難度有點大,還是放棄為妙。
最後
歡迎大家一起交流,喜歡文章記得關注我點個贊喲,感謝支援!