大家好括饶,我是大彬~
今天給大家分享最近出現(xiàn)的OOM問(wèn)題囊咏。
上周五早上恕洲,測(cè)試同學(xué)反饋測(cè)試環(huán)境的子系統(tǒng)服務(wù)一直超時(shí),請(qǐng)求沒(méi)有響應(yīng)梅割。
收到這個(gè)問(wèn)題之后霜第,我有點(diǎn)納悶,最近這個(gè)系統(tǒng)也沒(méi)有改動(dòng)代碼邏輯户辞,怎么會(huì)突然報(bào)服務(wù)超時(shí)的問(wèn)題泌类。為避免影響測(cè)試進(jìn)度,我趕緊登陸堡壘機(jī)查看日志底燎,看看到底啥情況刃榨。
首先先看系統(tǒng)負(fù)載情況弹砚,使用top
命令查看。發(fā)現(xiàn)其中某個(gè)Java進(jìn)程cpu一直持續(xù)停留在100%到200%之間喇澡。因?yàn)檫@個(gè)系統(tǒng)不涉及大量運(yùn)算的邏輯迅栅,所以可以猜到要不就是死循環(huán)的問(wèn)題,要不就是頻繁full gc導(dǎo)致晴玖。
查看系統(tǒng)日志發(fā)現(xiàn)读存,出現(xiàn)java.lang.OutOfMemoryError: Metaspace
,很明顯呕屎,元空間內(nèi)存溢出了让簿。
接著查看系統(tǒng)gc情況,使用以下命令查看秀睛。pid為對(duì)應(yīng)的Java進(jìn)程id尔当,通過(guò)top命令獲取。參數(shù)1000
表示每隔1000ms打印一次記錄蹂安。
<pre mdtype="fences" cid="n17" lang="java" spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background: rgb(51, 51, 51); position: relative !important; padding: 10px 10px 10px 30px; width: inherit; color: rgb(184, 191, 198); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">jstat -gc pid 1000</pre>
一看執(zhí)行結(jié)果椭迎,果不其然,full gc 從應(yīng)用程序啟動(dòng)到采樣時(shí)已經(jīng)觸發(fā)了幾百次田盈!這也是cpu一直100%的原因畜号。
其中還有另一個(gè)參數(shù) MC(元空間分配內(nèi)存大小)允瞧,已經(jīng)接近設(shè)置的最大元空間大屑蛉怼(配置的--XX:MaxMetaspaceSize=128m)。
這里也簡(jiǎn)單介紹下元空間述暂。
元數(shù)據(jù)是jdk8里特有的數(shù)據(jù)結(jié)構(gòu)痹升,jdk7是叫永久代,到了jdk8永久代就廢棄了畦韭,使用元空間替代疼蛾。元空間被分配在本地內(nèi)存中(非堆上),默認(rèn)不限制內(nèi)存使用艺配,可以使用 MaxMetaspaceSize 指定最大值察郁。
元空間由兩大部分組成
Klass Metaspace
,用來(lái)存klass的妒挎,klass是class文件在jvm里的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)绳锅。
NoKlass Metaspac
e,專(zhuān)門(mén)來(lái)存klass相關(guān)的其他的內(nèi)容酝掩,比如method鳞芙,常量池等,這塊內(nèi)存是由多塊內(nèi)存組合起來(lái)的。MC 就是
Klass Metaspace
以及NoKlass Metaspace
兩者總共分配的內(nèi)存大小原朝,單位是KB驯嘱。上圖中,MC已經(jīng)接近元空間設(shè)置的上限值喳坠,也就是此時(shí)元空間內(nèi)存已經(jīng)不夠用了鞠评,導(dǎo)致一直觸發(fā)full gc。
然后就是dump內(nèi)存進(jìn)行分析壕鹉,看看是什么原因?qū)е碌脑臻g內(nèi)存溢出剃幌。使用命令./jmap -dump:live,format=b,file=/xxx
導(dǎo)出內(nèi)存heap到xxx位置(hprof格式),然后使用MAT工具進(jìn)行分析晾浴。
將hprof文件導(dǎo)入MAT工具负乡,打開(kāi)內(nèi)存泄漏分析(涉及公司內(nèi)部源碼,所以打了馬賽克):
看到這個(gè)之后脊凰,就大概知道是什么問(wèn)題了抖棘。因?yàn)樽罱緝?nèi)部在推廣一個(gè)漏洞監(jiān)控工具,需要在服務(wù)端部署agent程序狸涌,這個(gè)工具會(huì)收集切省、監(jiān)控應(yīng)用程序運(yùn)行時(shí)函數(shù)執(zhí)行、數(shù)據(jù)傳輸帕胆,可以識(shí)別常見(jiàn)的安全缺陷和漏洞朝捆。而打碼的部分正是這個(gè)漏洞監(jiān)控工具的應(yīng)用包名,很可能是引入這個(gè)工具引起的問(wèn)題惶楼!
進(jìn)一步確認(rèn)問(wèn)題右蹦。打開(kāi)Histogram:
Shallow Heap 代表一個(gè)對(duì)象結(jié)構(gòu)自身所占用的內(nèi)存大小诊杆,不包括其屬性引用對(duì)象所占的內(nèi)存歼捐。
Retained Heap 是一個(gè)對(duì)象被 GC 回收后,可釋放的內(nèi)存大小晨汹,等于釋放對(duì)象的 Retained Heap 中所有對(duì)象的 Shallow Heap 的和豹储。
在Histogram視圖中,選中其中一個(gè)類(lèi)點(diǎn)擊鼠標(biāo)右鍵會(huì)彈出一個(gè)菜單淘这,選擇Merge shortest paths to GC Roots剥扣,查看當(dāng)前對(duì)象到GC Root的路徑,可以過(guò)濾一些類(lèi)型的引用铝穷。
結(jié)果如下:
占用內(nèi)存空間最多的就是漏洞監(jiān)控工具的類(lèi)钠怯,也基本可以確定問(wèn)題所在了。
最后把這個(gè)漏洞監(jiān)控工具去掉之后曙聂,重新部署之后晦炊,就不會(huì)出現(xiàn)服務(wù)超時(shí)的問(wèn)題了。
以上就是本期OOM問(wèn)題分析的整個(gè)過(guò)程~
碼字不易,如果覺(jué)得對(duì)你有幫助断国,可以點(diǎn)個(gè)贊鼓勵(lì)一下贤姆!
我是程序員大彬 ,專(zhuān)注Java后端硬核知識(shí)分享稳衬,歡迎大家關(guān)注~