當(dāng)發(fā)現(xiàn)服務(wù)器可能存在內(nèi)存泄漏時(怎么發(fā)現(xiàn)捺氢?頻繁gc但是堆內(nèi)存降不下來剪撬,進(jìn)程內(nèi)存爆了就有可能是發(fā)生內(nèi)存泄漏了),怎么去定位發(fā)生的原因以及解決的方法馍佑。
首先梨水,在分析內(nèi)存前可以先通過代碼猜測一下可能存在內(nèi)存泄漏的部分疫诽,因為線上要想拿到dump下來的出問題的服務(wù)器的內(nèi)存文件一般會耗時很久,這個時間我們可以通過分析最近的版本更新內(nèi)容雏亚、或者有沒有新添加的代碼導(dǎo)致了內(nèi)存泄漏摩钙,這個可以通過查看svn或者git的提交,內(nèi)存泄漏的問題也可能是跨版本的网持,比如更新的版本1出現(xiàn)的內(nèi)存泄漏,但是內(nèi)存增長很緩慢谬返,到版本2停服更新前都沒有暴露日杈,然后版本2維護(hù)的時間比版本1要長一些,結(jié)果內(nèi)存增長到瓶頸就掛了酿炸,當(dāng)然這是比較特殊的情況填硕。更多的還是當(dāng)前版本更新的內(nèi)容引起的鹿鳖。
java服務(wù)器我們可以讓運維使用:jmap -histo:live pid
命令,打印出異常進(jìn)程的對象數(shù)量信息姻檀,同時找一個線上正常的進(jìn)程的做對比涝滴,找出對象數(shù)量明顯異常的對象歼疮,jvm gc無法回收的最大可能性就是存在大量強引用的異常對象,并且這些對象持續(xù)增長缩麸,因為某些原因沒有被回收導(dǎo)致堆內(nèi)存一直增加直到達(dá)到設(shè)置參數(shù)的極限骤素。
如下圖所示:
終端分屏的上面為異常的對象數(shù)量济竹,下方為正常的霎槐,可以非常明顯的看出這個對象數(shù)量肯定是存在問題的,于是我們可以基本定位到這個類的代碼存在漏洞袭景。然后引用也有可能是聯(lián)動的,就是一個對象數(shù)量的增長會帶動另外一個對象數(shù)量同樣增長荒澡,因為對象1引用了對象2单山,對象1不釋放幅疼,那么對象2同樣也不會釋放,所以我們在找尋異常對象時同樣需要判斷該對象是不是源頭悴晰,是不是是被帶動增長的逐工。
這個需要怎么判斷呢泪喊?每個服務(wù)端肯定會有一個數(shù)據(jù)實體的,當(dāng)請求服務(wù)端時需要構(gòu)造這么一個對象饲帅,這里以游戲服務(wù)端為例瘤泪,在游戲服務(wù)端里面就是一個Player對象,玩家相關(guān)的模塊都會掛在這個對象上面赦邻,那么其實我們首先需要觀察的就是該對象數(shù)量是否異常实檀,如果該對象數(shù)量明顯不對膳犹,那么這個異常一般跟該對象的行為有關(guān),因為即使相關(guān)模塊出問題铐料,很難反過來影響該對象的增長,如果有那就更好找了柒凉,沒有則再繼續(xù)分析篓跛。
如我們上面的分析,可以發(fā)現(xiàn)ActivityService這個對象數(shù)量不對愧沟,而且這個也是跟Player對象有關(guān)系的央渣,那么我們就可以從這里入手。如果你在查閱ActivityService這個類的代碼已經(jīng)發(fā)現(xiàn)問題所在北启,那么當(dāng)然是皆大歡喜拔第,但是如果仍舊無法定位或者依舊存疑咕村,那么這個時候內(nèi)存應(yīng)該dump下來了,我們可以通過分析內(nèi)存進(jìn)一步確認(rèn)問題的原因蚊俺。
dump內(nèi)存可以使用指令:jmap -dump:live,format=b,file=heap.bin <pid>
分析內(nèi)存我們可以使用MAT(Memory Analysis Tools)工具懈涛,MAT工具的安裝和使用網(wǎng)上已經(jīng)有很多教程了,就不贅述了泳猬,該工具功能非常強大批钠,是分析Java堆內(nèi)存的利器。
我們先用MAT打開dump下來的二進(jìn)制文件得封,然后點擊 Histogram埋心,查看內(nèi)存中的對象數(shù)量:
我們先看我們首要懷疑的Player對象,可以看到目前有14437個對象忙上,這個對象是否正常我們對比正常服的情況,這里明顯是不對的疫粥,因此我們通過
MAT工具找到這些Player對象為什么不會被回收:
先分類一下該對象的引用茬斧,得出下圖結(jié)果:
可以發(fā)現(xiàn)只有2個軟引用的Player對象,其余的都是GC ROOT梗逮,如果存在GC ROOT项秉,對象就不會被回收。
然后我們繼續(xù)跟蹤這些對象是被什么強引用:
得到的結(jié)果是:
如圖可知库糠,有14425的定時器在引用著這些Player對象伙狐,因為這些future沒有在執(zhí)行完畢或者在玩家下線等條件去移除,導(dǎo)致這些定時器一直存在瞬欧,這個時候問題的根源就找到了贷屎,至于怎么去定位更細(xì)節(jié)的問題產(chǎn)生原因,這個就涉及具體的業(yè)務(wù)細(xì)節(jié)了艘虎。
當(dāng)然MAT的功能肯定不止這些唉侄,我們通過該工具查看到這些對象在內(nèi)存中具體的值,
如里面的每個task的內(nèi)容都可以查看到野建,同時還可以對比對象属划,這個工具非常好玩,有待繼續(xù)挖掘候生!
希望對你有所幫助同眯。
Regards,
codjust