現象
最近項目組從NET平台遷移到Java的Dubbo平台上,由於大家都是Java的生手,發生了蠻多的問題,以后一一記錄。現在解決一個遇到的關於Java程序內存泄露的問題。
特別說明
Java萌新,理解不到位的地方請指點一二
版本
- Java 1.8
- Dubbo 2.6.2
- Docker 18.0.2
系統環境
我們這里是Docker Swarm集群,三台機器組成,Dubbo服務隨機部署到三台機器上。
問題重現
上線了一個Dubbo服務,這個服務涉及到數據庫查詢、排序分析、第三方接口調用。
服務啟動初始內存占用500MB左右,每檢索一次,內存增加10MB到幾十MB不等,而且不釋放。持續增高,最高可以塞滿整個服務器的內存。
檢查問題
首先,由於我們是部署在Docker集群上的,所以得去容器內進行檢查,剛上線,所以基礎容器選擇的是JDK版本,沒有用JRE。因為JDK帶有很多的調試工具。
查看生產環境並導出heap.hprof
首先看看容器的運行情況:
docker stats
這是后面調試的時候截的圖,早期發現的時候,內存是4.8G。明顯內存占用過多了。
因為宿主是沒有任何java環境的,進容器內做內存分析。
docker exec -it 容器ID bash # 進入指定容器
jmap -histo 1 | head -n 30 # 通過jmap工具查看
jmap的檢查結果當時忘了截圖了,這里就不留存了,百度能搜到了,就一筆帶過。
現在導出heap.hprof
文件,方便用MAT
進行分析。
jmap -dump:format=b,file=heap.hprof 1
在docker容器內,PID 1 是服務進程,以上命令將會在當前目錄生成heap.hprof
文件,比較大,我的有1.2G。可以先壓縮了,再傳回來,進行分析。
使用MAT進行內存分析
獨立版下載地址:MAT
打開從服務器下載回來的heap.hprof
文件
點擊Leak Suspects
查看分析結果。
點擊Details
查看詳情
上圖可以看到,MAT分析結果表明,OcMapperFactory這個類有問題。
看看具體代碼:
這個OcMapperFactory
是用來封裝orika
的工具類,而orika
是一個對象映射工具。由於這里沒有用單例導致了內存的泄露。加上單例再看看:
重新測試,發現內存已經穩定。