java進(jìn)程的內(nèi)存分析 OOM
java項(xiàng)目?jī)?nèi)存溢出(OOM)的排查方法及原因分析
線上的項(xiàng)目崩了,第一步就是重啟服務(wù)圖片,然后排查下項(xiàng)目日志,沒發(fā)現(xiàn)異常,繼續(xù)排查代碼,也沒找到問題所在,我們真的是太菜了圖片,
重啟后,幾分鐘有崩了,瑟瑟發(fā)抖圖片。
然后開始進(jìn)程信息排查
先top命令查看了下資源消耗情況,發(fā)現(xiàn)異常的java服務(wù)cpu使用率達(dá)200%,內(nèi)存占用也極高,所以又通過jstat -gc xx命令查看了下java堆的狀況
主要觀察的是如下幾個(gè)指標(biāo)
YGC:新生代垃圾回收次數(shù)
YGCT:新生代垃圾回收消耗時(shí)間
FGC:老年代垃圾回收次數(shù)
FGCT:老年代垃圾回收消耗時(shí)間
GCT:垃圾回收消耗總時(shí)間
young gc次數(shù)多很正常,gc線程耗時(shí)很短,且不會(huì)影響其他線程。
而full gc次數(shù)也很多且耗時(shí)較長(zhǎng)就很奇怪了,因?yàn)槔夏甏惶赡芤幌戮陀羞@么多內(nèi)存占用
這才重啟多久啊?。?!
況且full gc的時(shí)候,會(huì)發(fā)生stop-the-world現(xiàn)象。即除了gc線程外,其他線程都會(huì)被暫停,正好和服務(wù)進(jìn)程還在,但info日志不再輸出的現(xiàn)象對(duì)應(yīng)?。。?br>
隨即通過jmap -dump:format=b,file=dump.txt 進(jìn)程號(hào) 命令,保存了當(dāng)時(shí)的堆快照文件,然后準(zhǔn)備進(jìn)行分析,看看老年代究竟放了些什么對(duì)象。
命令:
jmap -dump:format=b,file=dump.hprof 1273315
然后就會(huì)保存 進(jìn)程號(hào) = 1273315 的程序的堆快照文件
然后把這個(gè)文件下載下來,用 MemoryAnalyzer 工具進(jìn)行分析
如何使用MemoryAnalyzer內(nèi)存分析工具
下載的地址連接在
鏈接:https://pan.baidu.com/s/1Pi48eZhdEC7rNCKs9QDO_w
提取碼:y91z
界面如下
然后內(nèi)存分析界面如下
詳細(xì)使用方法完畢
下面是上述提供的生產(chǎn)級(jí)別的排除分析圖
點(diǎn)擊紅框處可查看調(diào)用方法棧
在當(dāng)時(shí)的分析結(jié)果里,圖1中堆占用率前三的點(diǎn)擊“see stacktrace”都指向同一處業(yè)務(wù)代碼:
調(diào)用了mybatis mapper去select,說明有三個(gè)線程運(yùn)行到那處代碼時(shí)都產(chǎn)生了大對(duì)象,直接耗盡了內(nèi)存,持續(xù)引發(fā)full gc。
后面分析了那段代碼邏輯,是根據(jù)用戶的某個(gè)查詢參數(shù)去關(guān)聯(lián)表查出商編號(hào),再去商戶表里查出對(duì)應(yīng)商戶,再遍歷組裝下數(shù)據(jù),再返回給前端。
但是寫這段代碼的同事,直接把關(guān)聯(lián)表查出的商編號(hào)作為參數(shù)去商戶表查,沒有判空,而查商戶表時(shí)對(duì)商編號(hào)有如下判斷
所以導(dǎo)致如果關(guān)聯(lián)表查出數(shù)據(jù)為空,這里不會(huì)根據(jù)customer_no去查,基本等同于全表查詢,而商戶表有300多萬條數(shù)據(jù),一次查詢會(huì)返回一個(gè)300多萬條數(shù)據(jù)的list!?。?br>
事故原因復(fù)盤
當(dāng)?shù)谝淮斡|發(fā)bug時(shí),jvm會(huì)把產(chǎn)生的大對(duì)象A1分配在新生代(如果此時(shí)新生代gc后內(nèi)存足夠的話)。
第二次觸發(fā)時(shí),新生代gc后內(nèi)存可能不夠放大對(duì)象A2了(比如第一次的請(qǐng)求還未結(jié)束,A1沒有被回收),jvm會(huì)直接把A2放在老年代。
第三,第四次觸發(fā)時(shí),產(chǎn)生的大對(duì)象A3,A4也放在了老年代。
可能第五次觸發(fā)時(shí),老年代內(nèi)存也不夠了,就會(huì)觸發(fā)full gc,一次full gc釋放的內(nèi)存不夠,就會(huì)繼續(xù)full gc。
而full gc時(shí),之前還未處理完的請(qǐng)求線程被暫停,大對(duì)象還在被引用,無法回收,就會(huì)像類似死循環(huán)一樣,一直full gc了
你學(xué)廢了。。。。。。
作者:老王
歡迎關(guān)注微信公眾號(hào) : IT學(xué)習(xí)道場(chǎng)