不知道從哪一天開始窝稿,項(xiàng)目每隔一段時(shí)間楣富,就會(huì)出現(xiàn)一次OOM問題,具體的表現(xiàn)就是伴榔,剛開始纹蝴,用戶請(qǐng)求變慢庄萎,隔幾分鐘后,所有的請(qǐng)求都沒有響應(yīng)塘安,最終服務(wù)出現(xiàn)FULL GC問題惨恭。
日志大概是這樣的:
最開始,以為是項(xiàng)目中緩存或者是數(shù)據(jù)庫配置的導(dǎo)致的問題耙旦,但是改了之后依然不行脱羡。
由于這個(gè)問題是偶現(xiàn)的,每次出現(xiàn)問題免都,為了項(xiàng)目正常使用锉罐,基本上都是直接重啟來解決。
終于有一天绕娘,服務(wù)又崩了脓规,于是下定決心要把這個(gè)問題找出來。
解決這種問題险领,離不開JVM的相關(guān)知識(shí)侨舆,以及java提供的一些工具。
分析問題
首先绢陌,使用 jstat 命令挨下,分析jvm的GC情況,
jstat -gcutil pid 1000 (pid是通過top命令找到的java線程的pid)
可以發(fā)現(xiàn)脐湾,O(老年代占用了大量的空間) 同時(shí)FGC頻繁回收臭笆,導(dǎo)致的問題。
接下來秤掌,就是通過 jmap命令愁铺,分析下內(nèi)存的使用情況了
jmap -histo:live pid | more (pid是通過top命令找到的java線程的pid)
我們的應(yīng)用,啟動(dòng)配置參數(shù)是這樣的 -Xms2560m -Xmx2560m
但是可以看到闻鉴,這其中 一個(gè)[B的class 茵乱,就占用了1.6G的內(nèi)存,這個(gè)[B是啥呢孟岛,他是JAVA中的byte數(shù)組瓶竭。
為啥byte數(shù)組會(huì)占用了這么多的內(nèi)存,我是滿腦子的問號(hào)蚀苛。
沒辦法在验,只能把內(nèi)存文件dump出來分析下了。
使用命令
jmap -dump:format=b,file=a.prof pid (pid是通過top命令找到的java線程的pid)
最終我們得到了一個(gè) a.prof的文件堵未,這個(gè)文件通常比較大腋舌,像我們的。足足2個(gè)G渗蟹,畢竟項(xiàng)目分配了2個(gè)G块饺,GC OOM導(dǎo)致都占用完了赞辩。
然后使用gzip 命令壓縮下,
gzip -q a.prof
壓縮后授艰,文件只有50M不到辨嗽,這樣就能方便下載下來分析了。
下載下來后淮腾,通過 MAT工具進(jìn)行分析糟需,關(guān)于這個(gè)工具,可以去網(wǎng)上找教程進(jìn)行下載安裝谷朝。
打開軟件后洲押,通過 File- Open Heap Dump 打開我們上面的dump文件。
然后點(diǎn)擊 Dominator Tree 圆凰,看下具體的占用
發(fā)現(xiàn)這其中杈帐,并沒有像網(wǎng)上那種,有一個(gè)單獨(dú)的對(duì)象占用了很大的內(nèi)存专钉,而是有很多個(gè)byte數(shù)組平均占用了內(nèi)存挑童,每個(gè)都占用了大概10M 的內(nèi)存,然后數(shù)量一多跃须,就導(dǎo)致了OOM站叼,通過className,可以發(fā)現(xiàn),是一個(gè)http請(qǐng)求路徑回怜。
這個(gè)路徑大年,在項(xiàng)目里面對(duì)的作用,是給三方渠道作為下載鏈接使用的玉雾,那為啥會(huì)這么多這個(gè)請(qǐng)求呢。
通過HTTP請(qǐng)求日志發(fā)現(xiàn)轻要,每次問題發(fā)生時(shí)复旬,都會(huì)有大量的請(qǐng)求調(diào)用這個(gè)接口,高峰大概每秒50+冲泥。
這個(gè)請(qǐng)求量驹碍,說大不大,說小也不小凡恍。正常單機(jī)tomcat對(duì)付這個(gè)志秃,應(yīng)該是問題不大的。但是為啥還出現(xiàn)這個(gè)問題呢嚼酝。
問題出現(xiàn)的原因浮还,是每個(gè)請(qǐng)求占用了10M的內(nèi)存導(dǎo)致的,最終我在配置文件里闽巩,看到了這么一行
max-http-header-size: 10000000
這個(gè)配置的作用钧舌,是配置請(qǐng)求頭最大值担汤,但是這就導(dǎo)致,一個(gè)請(qǐng)求進(jìn)來洼冻,tomcat就會(huì)申請(qǐng)10M的內(nèi)存空間崭歧,當(dāng)大量請(qǐng)求同時(shí)間進(jìn)來,內(nèi)存來不及釋放撞牢,最終導(dǎo)致了這個(gè)內(nèi)存泄漏的問題率碾。
解決辦法很簡(jiǎn)單,把這個(gè)值改小就行屋彪,正常項(xiàng)目一般100K就足夠了所宰。
終于把這個(gè)困擾了幾個(gè)月的問題解決了!:嘲唷歧匈!
關(guān)于 max-http-header-size的設(shè)置可以參考 https://www.baeldung.com/spring-boot-max-http-header-size
網(wǎng)上其他人碰到的這個(gè)問題 https://blog.csdn.net/xiaoming120915/article/details/120472272