有關OOM問題

1、OOM類型

OOM,即OutOfMemory,內存溢出,原因是:分配的太少;用的太多;用完沒釋放。

內存泄漏:內存用完沒有被釋放。大量的內存泄漏就會導致OOM,也就是內存溢出。

常見的OOM情況有三種:

  1. java.lang.OutOfMemoryError: Java heap space ------>java堆內存溢出,此種情況最常見,一般由於內存泄露或者堆的大小設置不當引起。對於內存泄露,需要通過內存監控軟件查找程序中的泄露代碼,而堆大小可以通過虛擬機參數-Xms,-Xmx等修改。
  2. java.lang.OutOfMemoryError: PermGen space/ Metaspace------>java永久代(元數據)溢出,即方法區溢出了,一般出現於大量Class或者jsp頁面,或者採用cglib等反射機制的情況,因爲上述情況會產生大量的Class信息存儲於方法區。此種情況可以通過更改方法區的大小來解決,使用類似-XX:PermSize/MetaspaceSize=64m -XX:MaxPermSize/MaxMetaspaceSize =256m的形式修改。另外,過多的常量也會導致方法區溢出。
  3. 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章