1、OOM類型
OOM,即OutOfMemory
,內存溢出,原因是:分配的太少;用的太多;用完沒釋放。
內存泄漏:內存用完沒有被釋放。大量的內存泄漏就會導致OOM,也就是內存溢出。
常見的OOM情況有三種:
java.lang.OutOfMemoryError
: Java heap space ------>java堆內存溢出,此種情況最常見,一般由於內存泄露或者堆的大小設置不當引起。對於內存泄露,需要通過內存監控軟件查找程序中的泄露代碼,而堆大小可以通過虛擬機參數-Xms,-Xmx等修改。java.lang.OutOfMemoryError
: PermGen space/ Metaspace------>java永久代(元數據)溢出,即方法區溢出了,一般出現於大量Class或者jsp頁面,或者採用cglib等反射機制的情況,因爲上述情況會產生大量的Class信息存儲於方法區。此種情況可以通過更改方法區的大小來解決,使用類似-XX:PermSize/MetaspaceSize=64m -XX:MaxPermSize/MaxMetaspaceSize =256m
的形式修改。另外,過多的常量也會導致方法區溢出。java.lang.StackOverflowError
------>不會拋OOM error,但也是比較常見的Java內存溢出。JAVA虛擬機棧溢出,一般是由於程序中存在死循環或者深度遞歸調用造成的,棧大小設置太小也會出現此種溢出。可以通過虛擬機參數-Xss來設置棧的大小。
2、OOM處理
2.1 OutOfMemoryError: Java heap space
異常(堆溢出)
將堆信息dump出來,進行分析,dump的方法有兩種:
——設置JVM參數-XX:+HeapDumpOnOutOfMemoryError,設定當發生OOM時自動dump出堆信息。
——用JDK自帶的jmap導出dump文件
導出hprof文件後,使用MAT進行內存鏡像分析,MAT進行分析主要看4個界面:
HistoGram:列出內存中的對象,對象的個數和大小
Retained Heap比Shallow Heap多了當前對象引用的對象的Shallow Heap。
Dominator Tree:列出線程,以及線程下各對象佔用的內存
通過Path to GC roots可以查看線程中完整的對象引用鏈
Top Consumers:通過圖形列出最大的Object,便於定位問題
Leak Suspects:自動分析內存泄漏原因
導致堆內存泄漏的常見原因:
——靜態集合類引起的內存泄漏:像HashMap、Vector等的使用最容易出現內存泄露,這些靜態變量的生命週期和應用程序一致,他們所引用的所有的對象Object也不能被釋放,因爲他們也將一直被Vector等引用着。
——當集合Set裏面的對象屬性被修改後,再調用remove()方法時不起作用。之所以不起作用,是因爲對象屬性修改後,對象的hashcode就變了,remove的時候就找不到了。
——監聽器。Listener未刪除。
——各種連接。比如數據庫連接、Socket連接、IO連接等,沒有顯式close掉。
——非靜態內部類。非靜態內部類會自動生成構造函數,並把外部類作爲構造函數的參數,這樣才能在內部類裏使用外部類的屬性和方法。但是這樣內部類會保留外部類的引用,如果內部類與外部類的生命週期不一致,就可能回收不了。
——單例模式。在單例對象中引用了其它對象,被引用對象永遠不會回收。
2.2 OutOfMemoryError: PermGen space/ Metaspace
異常(方法區溢出)
方法區裏面是類的類型信息,同樣藉助MAT分析Dump下來的內存鏡像。
一般產生的原因:
——不正確地使用反射生成大量的Class
——有大量的JSP
——類中過多地使用常量
——對類加載器使用緩存
2.3 OutOfMemoryError:GC overhead limit exceeded
用98%的時間去GC,但只能回收2%的內存,說明內存已經沒法回收了,很有可能是內存中的對象都是不可回收對象,導致無法GC。
2.4 StackOverflowError
異常(棧溢出)
這一類是線程異常,處理的方法是使用jstack輸出.out文件,然後分析每個線程棧的運行情況。
一般產生的原因:
——出現無限遞歸或死循環,局部變量不停地創建,導出棧溢出。
參考鏈接:https://www.jianshu.com/p/0744abda44cb