腦圖地址: https://naotu.baidu.com/file/0cfdc49ec32194ff306e656a2ef1d002
參考文章:
1.什麼是OOM
OOM,全稱“Out Of Memory”,翻譯成中文就是“內存用完了”,來源於java.lang.OutOfMemoryError。意思就是說,當JVM因爲沒有足夠的內存來爲對象分配空間並且垃圾回收器也已經沒有空間可回收時,就會拋出這個error(注:非exception,因爲這個問題已經嚴重到不足以被應用處理)
2.爲什麼會OOM
2.1) 分配的少了:比如虛擬機本身可使用的內存(一般通過啓動時的VM參數指定)太少
2.2) 應用用的太多,並且用完沒釋放,浪費了。此時就會造成內存泄露或者內存溢出
2.3) OOM的類型
2.3.1) JVM內存模型
==程序計數器:當前線程執行的字節碼的行號指示器,線程私有
==JAVA虛擬機棧:Java方法執行的內存模型,每個Java方法的執行對應着一個棧幀的進棧和出棧的操作
==本地方法棧:類似“ JAVA虛擬機棧 ”,但是爲native方法的運行提供內存環境。
==JAVA堆:對象內存分配的地方,內存垃圾回收的主要區域,所有線程共享。可分爲新生代,老生代
==方法區:用於存儲已經被JVM加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。Hotspot中的“永久代”。
==運行時常量池:方法區的一部分,存儲常量信息,如各種字面量、符號引用等
==直接內存:並不是JVM運行時數據區的一部分, 可直接訪問的內存, 比如NIO會用到這部分
2.4)OOM分析--heapdump
2.4.1) dump堆的內存鏡像
設置JVM參數-XX:
+HeapDumpOnOutOfMemoryError,設定當發生OOM時自動dump出堆信息。不過該方法需要JDK5以上版本
2.4.2) 使用JDK自帶的jmap命令
"jmap -dump:format=b,file=heap.bin <pid>" 其中pid可以通過jps獲取
2.4.3) 對dump出的文件進行分析
==mat: eclipse memory analyzer, 基於eclipse RCP的內存分析工具。
==jhat:JDK自帶的java heap analyze tool,可以將堆中的對象以html的形式顯示出來
==IBM HeapAnalyzer
3. OOM異常解決
3.1)java.lang.OutOfMemoryError:Java heap space
3.1.1) 內存模型
==Heap space(堆空間)
== Permgen(永久代)
3.1.2) 代碼示例
java -Xmx12m OOM
內存泄漏(沒有重寫equals)
3.1.3) 解決
增加堆空間 & 減少上述編程錯誤
3.2)java.lang.OutOfMemoryError:GC overhead limit exceeded
原因
示意你的應用程序在垃圾收集上花費了太多時間但卻沒有什麼卵用。默認超過98%的時間用來做GC卻回收了不到2%的內存時將會拋出此錯誤
代碼示例
無限循環加鍵值對
解決
可以在應用程序啓動時添加如下JVM參數-XX:-UseGCOverheadLimit,這樣並沒有解決任何問題,只是推遲了錯誤出現的時間, 如果你的應用程序確實內存不足,增加堆內存會解決GC overhead limit問題
修改程序
3.3)java.lang.OutOfMemoryError:Permgen space
原因
太多的類或者太大的類被加載到permanent generation(持久代)
代碼示例
生成的類太多
需要注意的是JDK8已經完全移除持久代空間,取而代之的是元空間(Metaspace),所以示例最好的JDK1.7或者1.6下運行
解決
【增加大小】解決初始化時的OutOfMemoryError
解決Redeploy時的OutOfMemoryError
分析dump文件:首先,找出引用在哪裏被持有,如下命令導出dump文件:jmap -dump:format=b,file=dump.hprof <process-id>
給你的web應用程序添加一個關閉的hook,或者在應用程序卸載後移除引用
解決運行時OutOfMemoryError
允許JVM卸載類:-XX:+CMSClassUnloadingEnabled配合GC算法 -XX:+UseConcMarkSweepGC
3.4)java.lang.OutOfMemoryError:Metaspace
原因
太多的類或太大的類加載到元空間
解決方案
增加其大小,更改啓動配置增加如下參數:-XX:MaxMetaspaceSize = 512m
刪除此參數來完全解除對Metaspace大小的限制(默認是沒有限制的)
3.5)java.lang.OutOfMemoryError:Unable to create new native thread
原因
當JVM向OS請求創建一個新線程時,而OS卻無法創建新的native線程時就會拋出Unable to create new native thread錯誤
代碼示例
代碼運行時,很快達到OS的線程數限制
解決
在OS級別增加線程數限制
減少創建的線程數量
3.6)java.lang.OutOfMemoryError:Out of swap space
原因
當應用程序向JVM native heap請求分配內存失敗並且native heap也即將耗盡時,JVM會拋出Out of swap space錯誤
往往是由操作系統級別的問題引起的:
1)操作系統配置的交換空間不足
2)系統上的另一個進程消耗所有內存資源
解決
升級機器以包含更多內存優化應用程序以減少其內存佔用
3.7)java.lang.OutOfMemoryError:Requested array size exceeds VM limit
原因
該錯誤由JVM中的native code拋出。 JVM在爲數組分配內存之前,會執行特定於平臺的檢查:分配的數據結構是否在此平臺中是可尋址的。
代碼示例
數組裏元素太多
3.8)Out of memory:Kill process or sacrifice child
原因
內存殺手(Out of memory killer)”。當內核檢測到系統內存不足時,OOM killer被激活,然後選擇一個進程殺掉
代碼示例
內存殺手(Out of memory killer)