線上現(xiàn)象(各種監(jiān)控?cái)?shù)據(jù))
1.公司項(xiàng)目在監(jiān)控平臺(tái)上開始報(bào)警(jvm堆內(nèi)存占用報(bào)警应结,F(xiàn)ullGC次數(shù)超頻率報(bào)警)
2.觀察具體的監(jiān)控圖標(biāo)(預(yù)發(fā)機(jī)器)
線程數(shù)平穩(wěn)(260左右)
-
方法監(jiān)控可以看到在fullGC比較頻繁時(shí)匀油,業(yè)務(wù)方法幾乎無響應(yīng)
線上配置(jvm配置,運(yùn)行時(shí)內(nèi)存分布)
-
項(xiàng)目版本:jdk8 ,spring 5, 默認(rèn)垃圾處理器 Parallel GC with 43 thread(s) -Xms800m -Xmx800m -XX:MaxPermSize=256m
2.運(yùn)行時(shí)jstat
3.運(yùn)行時(shí)jmap histo
4.heap
5.dump文件1G左右幸冻,不發(fā)了,稍后看一下MAT分析的圖表吧
邏輯分析(定位問題大致方向)
1.通過監(jiān)控和運(yùn)行時(shí)數(shù)據(jù)分析丰嘉,堆內(nèi)存(年輕代和老年代)茄靠、非堆(方法區(qū))、均打滿配置內(nèi)存
2.即使FullGC,堆內(nèi)存和非堆也只能回收少許內(nèi)存忆首,并且整體水位傾斜向上爱榔,直到內(nèi)存溢出
通過邏輯分析,內(nèi)存溢出問題來自于存在泄漏糙及,接下來分析dump文件
內(nèi)存分析(定位問題確切泄漏源)
采用MAT工具載入dump文件進(jìn)行l(wèi)eak分析
通過分析可以看出紅色的業(yè)務(wù)方法保留引用太多, 找到泄漏源了详幽,接下來就分析業(yè)務(wù)代碼具體的問題
代碼分析(定位導(dǎo)致泄露代碼片段)
通過分析,我們最終定位了這段代碼丁鹉,我們改造過程中引入了一個(gè)開源的屬性運(yùn)行時(shí)拷貝的包
但是我們每次轉(zhuǎn)換的時(shí)候都會(huì)先register一遍轉(zhuǎn)換代理類妒潭,而此類底層為每次register注冊一個(gè)新生的代理類被加載到非堆
但是又被業(yè)務(wù)代碼中的MAPPER_FACTORY引用,導(dǎo)致每次生成的實(shí)例充斥著年輕代又到老年代
最終的現(xiàn)象就是老年代揣钦、年輕代雳灾、非堆內(nèi)存同時(shí)爆滿,而又GC不掉冯凹,內(nèi)存泄露直到溢出
代碼處理
找到了具體的代碼問題谎亩,我們將同一個(gè)類轉(zhuǎn)換的register在系統(tǒng)啟動(dòng)時(shí)注入一次就行,不用每次調(diào)用注冊宇姚,這樣的話就不會(huì)頻繁創(chuàng)建和加載匈庭,就可以解決上述問題
本地驗(yàn)證
本地驗(yàn)證錯(cuò)誤使用代碼,可以復(fù)現(xiàn)問題
加入 參數(shù)-verbose -verbose:gc
也 可以看到新增的代理類在循環(huán)中瘋狂生成與加載浑劳,
修復(fù)后本地監(jiān)控?cái)?shù)據(jù)平穩(wěn)運(yùn)行阱持,具體圖標(biāo)參考預(yù)發(fā)驗(yàn)證圖表
預(yù)發(fā)驗(yàn)證
預(yù)發(fā)驗(yàn)證后續(xù)我們還將采用壓測排除性能與其他內(nèi)存問題,此次排除結(jié)束魔熏。
后記
此次問題還是屬于比較常見的內(nèi)存溢出分析衷咽,整體按著常用流程沒有太多的難點(diǎn),只有在分析register的時(shí)候一時(shí)定位不到是開源包的register方法調(diào)用的原因(雖然事后感覺很簡單蒜绽,當(dāng)時(shí)也是耗費(fèi)了30分鐘左右才發(fā)現(xiàn))镶骗。
troube shooting 三要素: 鍛煉自己的邏輯思維、鍛煉自己的技術(shù)能力躲雅、多看多查