一次老生代內存使用占比飆升問題解決
老生代內存使用占比圖示
如圖所示老生代內存占比不斷增加,超過80%系統自動報警,之前的解決方案是手動重啟😜。
1、保存現場
為了解決上面老生代問題,首先需要dump下堆文件
命令:
ps -ef|grep DialingRobot
DialingRobot是服務名稱,找到對應的pid
pid:70992
dump堆內存
jmap -dump:format=b,file=1.dump 70992
將堆內存dump下來
為了分析內存的變化,可以在不同的時間進行dump操作,可以分析前后的內存變化,更方便查找問題
2、分析問題
1、jprofiler分析dump文件
將文件重命名為20200520.hprof(.hprof是可以分析的堆文件)
打開后長這樣
可以去看一下biggest對象
點開之后發現,占有內存比較大是正常的,這些類里面都存放着大量的內存緩存。
第二考慮是不是這個類太多了,沒有釋放,分析兩個時間段的堆內存,兩個dump中的這個對象的數量大小差異不大。嘗試mat去分析下dump文件。
2、mat分析dump文件
主要使用兩個模塊:Histogram和LeakSuspects
Histogram主要展示堆內的各個對象的大小
將兩個hprof文件導入mat,可以使用比較去分析兩個內存的前后的變化
兩個hprof文件前后對象的差異、內存的差異
分析這些差異,沒有看到什么有用的信息。
嘗試使用第二個mat的工具:Leak Suspects
mat給出兩個suspect,可以分析下,第一個還是之前的class文件過大,但是是由於內部維護了一部分緩存造成的,第二個cs csSocket也不是,跟JProfiler差異不大。
這個時候分析到達一個比較艱難的時候。
這個時候查看下jvm的參數設置:
可以看出來整個堆的大小是:1g,新生代是256mb,老年代是1024-256=768mb,看上去沒有什么問題。
這個時候需要分析我們的應用,我們的應用中的對象的特征,我們應用中的對象很少有需要一直存在的對象,更多是朝生夕死的對象,這樣的話,這個的是不是有問題呢?
我們去看看新生代的內存、回收情況。
可以看出來,老生代內存使用率的增加和新生代的gc強相關,新生代gc一次,老生代的內存使用率升高一點
3、解決問題
修改jvm參數
將堆內存從1g->2g,新生代256m->1024m,觀察老生代情況。
可以看出來:老生代內存使用占比穩定,新生代回收頻率也降低了很多(13 -> 3 /30min),單次耗時:(10ms -> 20ms),30分鍾內gc時間從130ms -> 60ms,降低了一倍
由此可見,服務中存在大量短期臨時對象,擴容新生代空間后,Minor GC頻率降低,對象在新生代得到充分回收,只有生命周期長的對象才進入老年代。這樣老年代增速變慢,Major GC頻率自然也會降低。