您好,歡迎來到網暖!
?
當前位置:網暖 » 站長資訊 » 建站基礎 » 網絡技術 » 文章詳細 訂閱RssFeed

1篇文章搞清楚8種JVM內存溢出(OOM)的原因和解決方法

來源:網絡整理 瀏覽:205次 時間:2019-12-08

前言

擼Java的同學,多多少少會碰到內存溢出(OOM)的場景,但造成OOM的原因卻是多種多樣。

v2-9a0d4c2ca70e4574a98c00aeba4c32cc_hd.png

堆溢出

這種場景最為常見,報錯信息:

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

v2-b26a29f62e69256653075aa6e05ce75d_hd.png

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)就會拋出這個錯誤。

解決方法就是檢查你的代碼中是否有創建超大數組的地方。

v2-7daa361860ef4ee83a6f1748a71a04d4_hd.png

swap溢出

報錯信息 :

java.lang.OutOfMemoryError:?Out?of?swap?space

這種情況一般是操作系統導致的,可能的原因有:

1、swap 分區大小分配不足;

2、其他進程消耗了所有的內存。

解決方案:

1、其它服務進程可以選擇性的拆分出去 2、加大swap分區大小,或者加大機器內存大小

本地方法溢出

報錯信息 :

java.lang.OutOfMemoryError:?stack_trace_with_native_method

本地方法在運行時出現了內存分配失敗,和之前的方法棧溢出不同,方法棧溢出發生在 JVM 代碼層面,而本地方法溢出發生在JNI代碼或本地方法處。

這個異常出現的概率極低,只能通過操作系統本地工具進行診斷,難度有點大,還是放棄為妙。

最后

歡迎大家一起交流,喜歡文章記得關注我點個贊喲,感謝支持!


推薦站點

  • 騰訊騰訊

    騰訊網(www.QQ.com)是中國瀏覽量最大的中文門戶網站,是騰訊公司推出的集新聞信息、互動社區、娛樂產品和基礎服務為一體的大型綜合門戶網站。騰訊網服務于全球華人用戶,致力成為最具傳播力和互動性,權威、主流、時尚的互聯網媒體平臺。通過強大的實時新聞和全面深入的信息資訊服務,為中國數以億計的互聯網用戶提供富有創意的網上新生活。

    www.qq.com
  • 搜狐搜狐

    搜狐網是全球最大的中文門戶網站,為用戶提供24小時不間斷的最新資訊,及搜索、郵件等網絡服務。內容包括全球熱點事件、突發新聞、時事評論、熱播影視劇、體育賽事、行業動態、生活服務信息,以及論壇、博客、微博、我的搜狐等互動空間。

    www.sohu.com
  • 網易網易

    網易是中國領先的互聯網技術公司,為用戶提供免費郵箱、游戲、搜索引擎服務,開設新聞、娛樂、體育等30多個內容頻道,及博客、視頻、論壇等互動交流,網聚人的力量。

    www.163.com
  • 新浪新浪

    新浪網為全球用戶24小時提供全面及時的中文資訊,內容覆蓋國內外突發新聞事件、體壇賽事、娛樂時尚、產業資訊、實用信息等,設有新聞、體育、娛樂、財經、科技、房產、汽車等30多個內容頻道,同時開設博客、視頻、論壇等自由互動交流空間。

    www.sina.com.cn
  • 百度一下百度一下

    百度一下,你就知道

    www.baidu.com
?
买北京单场