【OOM】記一次線上OOM解決全流程


一、OOM背景

  疫情期間,大家都開始了遠程辦公。剛開始不適應,最后感覺還挺好的,不用每天擠地鐵,住8平米的出租屋。

  忽然有一天,系統報警郵件來了,運維也在群里艾特我,系統OOM了。其實寫Java的同學如果自己負責的系統出現了OOM,是很尷尬的事情。

  畢竟也是骨灰級玩家了,不慌不忙。考慮到遠程機器的不便,我果斷要求運維拿下dump.hprof文件給我。沒想到運維說並沒有輸出,我此時也不想過問為何沒輸出了。可能運維把啟動參數去掉了,也可能內存占用太大了輸出不了。。。

  好吧!那就強制輸出下吧!jmap -dump:live,format=b,file=/tmp/application.hprof pid   一條強制輸出內存日志的命令扔給運維同學。順利拿到了文件。拿到內存文件后(3個G的dump.hprof),運維暫時重啟了本服務。

  其實這個項目以前運維找我說過,項目跑一段時間后,內存占用大概就在1.5G-2G之間(這個項目作為本公司並發最大的項目之一,我們給了4G內存),我本想抽個時間好好分析下內存占用的,后來事情比較多,反正項目還能繼續用,也就暫時擱置了。(可能是創業公司的通病,一切以暫時能用為目標!)

 

二、解決思路

       拿到dump.hprof文件,我打開了神器--“MemoryAnalyzer”  (https://www.cnblogs.com/kbian/p/11780508.html),本次內存溢出的錯誤:java.lang.OutOfMemoryError: Java heap space。堆內存占用過高!我就看看哪些東西吃了了這么多內存,新賬舊賬一塊算!直接打開直方圖

 這個byte[]占用了1.5G,繼續深究!看看是哪些對象。with all references

 

 

看不知道,一看嚇一跳,好多個tomcat線程,每個占用了20M

 

 

點開其中一個線程繼續跟蹤!可以看到很明顯這和HTTP請求相關。

tomcat的線程在處理過程中分配了10M的buffer在堆上,一個線程分配了輸入輸出兩個buffer,占用20M內存。

馬上可以想到可能是tomcat什么參數設置的不合理導致了這種情況,一個請求線程不可能占用20M。趕緊看看application.yml

 

果然,http的header分配了10M的內存!輸入加輸出,一個線程20M沒錯了!

 

三、驗證

  在測試環境將 max-http-header-size直接去掉。(默認值只有 4096 個字節(4k)),push代碼,發布完成!跑了幾個小時,讓運維同學看了下,該項目從常用內存2G變為了700M!拿到dump.hprof文件看了下,20M的tomcat請求已經不存在了。

       嗯!700M?現在春節放假,並發不多,還有優化空間嘛!下次再說了!

 

四、復盤

  為何max-http-header-size 設置為10M就會占用20M呢?其實我看了header里面的內容,不超過1K。

  查閱資料說,tomcat每次一個http線程,都會開啟 input headerbuffer、output headerbuffer。一個headerbuffer分配的大小是:MaxHttpHeaderSizeReadBuffer + ReadBuffer。ReadBuffer默認是8K。

       這就對了!

 

五、小結

  1、知其然知其所以然!不通源碼的程序員不是一個架構師!源碼學習之路任重道遠。。。

  2、寫代碼腦子里要裝着JVM,OOM是程序員之恥。。。。。千萬不要犯

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM