生產出現oom問題,怎麼排查?

一、使用dmesg命令查看系統日誌java

dmesg |grep -E ‘kill|oom|out of memory’,能夠查看操做系統啓動後的系統日誌,這裏就是查看跟內存溢出相關聯的系統日誌mysql

 

二、這時候,須要啓動項目,使用ps命令查看進程面試

ps -aux|grep java命令查看一下你的java進程,就能夠找到你的java進程的進程idsql

 

三、接着使用top命令緩存

top命令顯示的結果列表中,會看到%MEM這一列,這裏能夠看到你的進程可能對內存的使用率特別高。以查看正在運行的進程和系統負載信息,包括cpu負載、內存使用、各個進程所佔系統資源等框架

 

 

 

四、使用jstat命令jvm

jstat -gcutil 20886 1000 10命令,就是用jstat工具,對指定java進程(20886就是進程id,經過ps -aux | grep java命令就能找到),按照指定間隔,看一下統計信息,這裏會每隔一段時間顯示一下,包括新生代的兩個S0、s1區、Eden區,以及老年代的內存使用率,還有young gc以及full gc的次數。工具

 

 

 

使用 jstat -gcutil 8968 500 5 表示每500毫秒打印一次Java堆情況(各個區的容量、使用容量、gc時間等信息),打印5次性能

 

 

 

例如:優化

看到的東西相似下面那樣:

S0       S1     E            O         YGC  FGC

26.80   0.00   10.50    89.90    86     954

 

其實若是你們瞭解原理,應該知道,通常來講大量的對象涌入內存,結果始終不能回收,會出現的狀況就是,快速撐滿年輕代,而後young gc幾回,根本回收不了什麼對象,致使survivor區根本放不下,而後大量對象涌入老年代。老年代很快也滿了,而後就頻繁full gc,可是也回收不掉。

而後對象持續增長不就oom了,內存放不下了,爆了唄。

因此jstat先看一下基本狀況,立刻就能看出來,其實就是大量對象無法回收,一直在內存裏佔據着,而後就差很少內存快爆了。

 

 

 

五、使用jmap命令查看

執行jmap -histo pid能夠打印出當前堆中全部每一個類的實例數量和內存佔用,以下,class name是每一個類的類名([B是byte類型,[C是char類型,[I是int類型),bytes是這個類的全部示例佔用內存大小,instances是這個類的實例數量。

 

 

 

 

六、把當前堆內存的快照轉儲到dumpfile_jmap.hprof文件中,而後能夠對內存快照進行分析

 

使用jmap -dump:format=b,file=文件名 [pid],就能夠把指定java進程的堆內存快照搞到一個指定的文件裏去,可是jmap -dump:format其實通常會比較慢一些,也能夠用gcore工具來導出內存快照

 

例如:jmap -dump:format=b,file=D:/log/jvm/dumpfile_jmap.hprof 20886

 

 

 

 

接着就是能夠用MAT工具,或者是Eclipse MAT的內存分析插件,來對hprof文件進行分析,看看究竟是哪一個王八蛋對象太多了,致使內存溢出了

 

 

 

 

或者使用jdk的目錄下的bin目錄下的:jvisualvm.exe

 

 

 

八、總結:

通常常見的OOM,要麼是短期內涌入大量的對象,致使你的系統根本支持不住,此時你能夠考慮優化代碼,或者是加機器;要麼是長時間來看,你的不少對象不用了可是還被引用,就是內存泄露了,你也是優化代碼就行了;這就會致使大量的對象不斷進入老年代,而後頻繁full gc以後始終無法回收,就撐爆了

 

要麼是加載的類過多,致使class在永久代理保存的過多,始終沒法釋放,就會撐爆

 

我這裏能夠給你們最後提一點,人家確定會問你有沒有處理過線上的問題,你就說有,最簡單的,你說有個小夥子用了本地緩存,就放map裏,結果沒控制map大小,能夠無限擴容,最終致使內存爆了,後來解決方案就是用了一個ehcache框架,自動LRU清理掉舊數據,控制內存佔用就行了。

 

另外,務必提到,線上jvm必須配置-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/path/heap/dump。由於這樣就是說OOM的時候自動導出一分內存快照,你就能夠分析發生OOM時的內存快照了,究竟是哪裏出現的問題

 

九、修改代碼調優,修改jvm配置調優,部署接口壓測

代碼進行優化、根據壓測的狀況去進行必定的jvm參數的調優,一個系統的QPS,一個是系統的接口的性能,壓測到必定程度的時候 ,機器的cpu、內存、io、磁盤的一些負載狀況,jvm的表現

 

十、流程

 

附加:系統頻繁full gc

OOM稍微好點的是頻繁full gc,若是OOM就是系統自動就掛了,很慘,你絕對是超級大case,可是頻繁full gc會好多,其實就是表現爲常常請求系統的時候,很卡,一個請求卡半天沒響應,就是會以爲系統性能不好。

 

首先,你必須先加上一些jvm的參數,讓線上系統按期打出來gc的日誌:

 

-XX:+PrintGCTimeStamps

-XX:+PrintGCDeatils

-Xloggc:<filename>

 

這樣若是發現線上系統常常卡頓,能夠當即去查看gc日誌,大概長成這樣:

 

 

若是要是發現每次Full GC事後,ParOldGen就是老年代總是下不去,那就是大量的內存一直佔據着老年代,啥事兒不幹,回收不掉,因此頻繁的full gc,每次full gc確定會致使必定的stop the world卡頓,這是不可能徹底避免的

 

接着採用跟以前同樣的方法,就是dump出來一分內存快照,而後用Eclipse MAT插件分析一下好了,看看哪一個對象量太大了

 

接着其實就是跟具體的業務場景相關了,要看具體是怎麼回事,常見的其實要麼是內存泄露,要麼就是類加載過多致使永久代快滿了,此時通常就是針對代碼邏輯來優化一下。

 

給你們仍是舉個例子吧,咱們線上系統的一個真實例子,你們能夠用這個例子在面試裏來講,好比說當時咱們有個系統,在後臺運行,每次都會一會兒從mysql里加載幾十萬行數據進來各類處理,相似於定時批量處理,這個時候,若是對幾十萬數據的處理比較慢,就會致使好比幾分鐘裏面,大量數據囤積在老年代,而後無法回收,就會頻繁full gc。

 

當時咱們其實就是根據這個發現了當時兩臺機器已經不夠了,由於咱們當時線上用了兩臺4核8G的虛擬機在跑,明顯不夠了,就要加機器了,因此增長了機器,每臺機器處理更少的數據量,那不就ok了,立刻就緩解了頻繁full gc的問題了。

相關文章
相關標籤/搜索