一要拂、問題場景
在一個(gè)短信平臺的項(xiàng)目中巴比,設(shè)置了一個(gè)下發(fā)節(jié)點(diǎn)的Xmx為16G术奖,但是出現(xiàn)了內(nèi)存撐滿礁遵,導(dǎo)致CPU過高的情況。當(dāng)時(shí)的具體情況是采记,該應(yīng)用內(nèi)存占用16G佣耐,該應(yīng)用CPU占用1400%(16核),服務(wù)器負(fù)載15左右唧龄。進(jìn)入應(yīng)用的實(shí)時(shí)日志兼砖,發(fā)現(xiàn)日志每打印四五秒后,會(huì)暫停一分多鐘既棺。這代表著由于內(nèi)存耗盡讽挟,導(dǎo)致cpu高負(fù)載,最終導(dǎo)致應(yīng)用程序不能正常運(yùn)行丸冕,斷斷續(xù)續(xù)耽梅。嚴(yán)重影響生產(chǎn)環(huán)境的運(yùn)行速率。
二胖烛、解決方案
1眼姐、線上救急的臨時(shí)方案:
(1)讓運(yùn)營停止審核,即停止繼續(xù)往堵塞應(yīng)用中送數(shù)據(jù)佩番。
內(nèi)存隊(duì)列中的數(shù)據(jù)讓它慢慢下放众旗,經(jīng)過幾個(gè)小時(shí)的下放后,斷斷續(xù)續(xù)由每次四五秒到十幾秒最終到幾十秒答捕,當(dāng)內(nèi)存隊(duì)列中的數(shù)據(jù)全部清空后,斷斷續(xù)續(xù)仍然存在屑那,但是要好了很多拱镐,基本是正常半分鐘,暫停半分鐘持际。這時(shí)候內(nèi)存占用仍然沒有明顯的下降沃琅。
(2)重啟服務(wù),內(nèi)存當(dāng)即釋放掉蜘欲,所有問題得到了臨時(shí)解決益眉。
(3)將應(yīng)用的Xmx由16G調(diào)高到52G,服務(wù)器是64G內(nèi)存的姥份。
(4)時(shí)刻關(guān)注這臺服務(wù)器的內(nèi)存cpu占用郭脂,每晚凌晨重啟。
2澈歉、解決根本問題展鸡,有參考 https://www.javazhiyin.com/34154.html
(1)輸入命令:top -c,查看占用內(nèi)存過高的進(jìn)程信息
(2)輸入命令:jmap -histo:live PID > xxx.log埃难,vim查看內(nèi)存中的存活對象統(tǒng)計(jì)莹弊,找出業(yè)務(wù)相關(guān)的類名
(3)如果第(2)步仍然不能定位到代碼中的具體對象涤久,輸入命令:jmap -dump:live,format=b,file=xxx.hprof PID
這個(gè)命令會(huì)將內(nèi)存里的所有信息都輸出,生成hprof文件忍弛。我16G的內(nèi)存占用响迂,輸出的文件大小為1.6G。注意:這個(gè)命令會(huì)導(dǎo)致應(yīng)用暫時(shí)掛起细疚,所以謹(jǐn)慎使用蔗彤。我的應(yīng)用當(dāng)時(shí)掛起了約10s。
(4)文件大小不是很大的話惠昔,使用jdk自帶的jhat命令即可幕与,輸入命令:jhat -J-mx2G -port 7170,該命令可以查看內(nèi)存占用的對象
(5)如果文件太大镇防,可以下載到本地使用jdk自帶的 jvisualvm 工具進(jìn)行分析啦鸣。下面詳細(xì)講怎么使用jvisualvm定位內(nèi)存占用問題。
二来氧、使用jvisualvm定位內(nèi)存占用問題
1诫给、jvisualvm.exe的文件路徑在java安裝路徑的bin目錄下
我的是 C:\Program Files\Java\jdk1.8.0_60\bin
2、打開儲存堆信息的 hprof 文件
(1)注意圖中 文件類型 選擇【堆 Dump(啦扬。hprof中狂,.*)】,否則hprof文件不會(huì)顯示
(2)設(shè)置jvisualVM的啟動(dòng)堆內(nèi)存
在使用 jvisualVM 的時(shí)候,加載1.6G的 hprof 文件扑毡,提示內(nèi)存不足胃榕,然后中斷。原來 jvisualVM 也需要設(shè)置java堆內(nèi)存瞄摊,于是修改Java_home/lib/visualvm/etc/visualvm.conf 文件中 visualvm_default_options="-J-client -J-Xms24 -J-Xmx256m",把256調(diào)大勋又,本案例中設(shè)置成了1024m,然后重啟jvisualVM即可
3、如果有內(nèi)存泄漏换帜,概要界面會(huì)顯示它的線程楔壤,
本案例中不存在內(nèi)存泄漏問題
4、進(jìn)入界面具體分析
(1)如圖惯驼,點(diǎn)擊【類】蹲嚣,可以看到占用 內(nèi)存較多的對象。
如果有應(yīng)用代碼中的對象祟牲,那么就破案了隙畜。此案例中 TbKeywordBan占用較高,但是應(yīng)該不是主因说贝。
(2)我們分別雙擊點(diǎn)開占用內(nèi)存很多的 HashMap$Node禾蚕、AtomicInteger、Long狂丝。觀察引用他們的父級對象换淆。
多點(diǎn)開幾個(gè)進(jìn)行觀察哗总,都發(fā)現(xiàn)了 ExpiryMap 這個(gè)類,到此處倍试,就已經(jīng)破案了讯屈。