jprofiler分析dump文件_内存溢出+CPU占用过高:问题排查+解决方案+复盘(超详细分析教程)...
點擊上方 "Java指南者"關注,?星標或置頂一起成長
免費送 1024GB 精品學習資源?
來源:https://zhanghan.blog.csdn.net/article/details/109255980
前言
最近剛上線了一款社交項目,運行十多天后(運營持續每天推量),發現問題:
- 系統 OOM(資源不能被釋放)導致服務器頻繁且長時間 FGC 導致服務器 CPU 持續飚高
- 日志中內存溢出:java.lang.OutOfMemoryError: Java heap space
- 程序十分卡頓,嚴重影響用戶使用
從以下方面,為大家分享此次問題解決流程
- 問題出現現象
- 臨時解決方案
- 復現問題
- 定位問題發生原因
- 優化代碼
- 優化后進行壓測,上線
- 復盤
學完本博文,你的收獲
- 排查內存溢出的思路
- 排查內存溢出過程中用到的命令及工具(Linux 命令,Eclipse Memory Anaylzer[MAT])
- 定位系統內存溢出的代碼,并進行優化
- 此次內存溢出問題復盤
- 解決方案流程圖
問題&臨時解決方案&定位問題&最終解決方案
問題:
業務反饋程序用的十分卡,同時測試自己測的也十分卡
從 ELK 收集的請求日志發現確實存在問題,線上是兩臺部署:兩臺機器上都是,一次請求耗時由原來的幾毫秒變為 10 幾秒
CPU 跑的過高,當時是 4 核,CPU 持續飆到 350%+;
當時一臺服務器 CPU 截圖:
臨時解決方案
- 當時為了減少對業務影響,直接將生產兩臺服務器上的項目進行重啟
- 項目啟動參數中沒有加內存溢出日志輸出(后續博客為大家介紹 JVM 調優時講解啟動命令中加內存溢出日志輸出),重啟后出問題時項目的 JVM 信息丟失了
復現問題方式:在開發環境對程序進行持續壓測;壓測相關服務器配置:
服務器配置:8 核,16G
項目啟動內存:136M
Jmeter 持續(循環)壓發消息接口 10 分鐘
定位問題
top 命令查看最耗 CPU 的進程(進程:17038;CPU 持續飆到 595%+)
#?輸入top命令后鍵入P(大寫P),進程按照CPU從高到底排序top
- 查看該進程中最耗 CPU 的線程(發現有一些線程占用 CPU 較高)
top?-Hp?17038
- 將線程號轉為 16 進制,同時查看這些線程當前正在干什么(在此以 17045 線程為例
printf?'%x\n'?17045
#?17038為進程號,0x4295為最耗CPU線程的十六進制
jstack?17038?|?grep?'0x4295'?-C10?--color
可以看到最耗 CPU 的線程都是在進行 GC
用 Jmap 命令查看當前堆的使用情況(發現老年代現在已占用 99.8%+)
jmap?-heap?17038
- 查看 gc 頻率的命令(其中 O 代表老年代占用率,FGC 是 FullGC 次數,FGCT 是 fullGC 時間;可以看出在頻繁 FullGC 但是老年代有資源一直釋放不掉)
jstat?-gcutil?17038?5000
- 通過分析出問題時線上日志發現內存溢出;至此定位到問題根源是內存溢出導致(有未釋放資源堆積,導致老年代被占滿,然后頻繁的 FullGC 但是資源一直釋放不了)
分析問題產生原因
由于線上當時直接重啟,未能保留當時的 JVM 內存文件;在開發環境進行循環壓測,復現線上問題,然后導出 dump 文件進行分析找到原因
生成 dump 文件命令
jmap?-dump:format=b,file=fileName.dump?pid
1
2
將 dump 文件導出到本地,用 Eclipse Memary Analysis(MAT 官網下載地址) 進行分析
MAT 導入 dump 文件
- 按對象排序視圖進行查看(總覽中看到對象總個數:14.1 百萬個)
- 發現有兩個類(ClassClassPath,ClassClassPathList)占用比較大,這兩個類約占對象總數的 83%(計算方式:5873361*2/14100000=83%)
分析代碼
- 去代碼中全局搜這兩個類,發現只有在打日志的時候用到 ClassClassPath 類
分析 ClassClassPath 相關代碼:
用到 ClassClassPath 對象是一個靜態的 ClassPool;
問題原因:classPath 一直被靜態的全局 pool 所持有,導致 GC 一直釋放不掉;
- 當然順著代碼,順藤摸瓜也找到了 ClassPathList
優化代碼:每次用完 ClassClassPath 后將其釋放
每次對象使用完后從靜態 pool 中移除
注意:classPath=null 這種方式是不能釋放掉的
優化后再次進行驗證
- 開發環境循環壓測,用 MAT 分析 dump 文件,發現內存中已不再堆積 ClassClassPath 類;優化前后接口吞吐量也提升 8.2%
- 進行線上發布,觀察一周后,對內存分析發現正常
復盤:
項目比對:
為快速開發,社交的代碼從原來金融項目基礎上改造而來;
原來金融項目沒有內存溢出,而社交項目為什么內存溢出?
通過 ELK 統計一段時間的訪問量結果:
- 社交目前日訪問后臺量 65w+
- 金融項目只有 4.5W+
社交和金融項目業務類型不一樣,所呈現出的特點也不同
去生產的金融項目中 dump 內存文件,用 MAT 工具分析,發現也存在 ClassClassPath 類堆積釋放不掉,只不過由于訪問量少,堆積量未占滿老年代而已;果斷在金融項目迭代時將其優化;
程序預警:為減少業務影響,增加接口耗時的預警(后續博文為大家共享);實現方式:
在每次程序處理完進行預警(比如本次請求>閾值);缺點:消耗性能影響正常業務
在 ELK 清洗時用相關插件進行預警;優點:和業務解耦,對業務無影響
服務器預警:運維增加 CPU 內存,日志內存溢出監控
總結
解決內存溢出過程總結:
不同的項目導致內存溢出原因是不同的;
重要的是排查思路
經過不斷的耐心的去觀察,測試,分析才能定位到問題并最終解決問題
在這次分析內存溢出過程中,我們也針對我們項目的 JVM 啟動參數進行了調優,在接下來的博文中為大家分享 JVM 調優
熱門內容:
兩年經驗斬獲螞蟻/頭條/PingCAP Offer,牛逼了
字節跳動熱騰騰的面經分享深入理解 Java 內存模型關注我
關注我,Java 學習不迷路!
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的jprofiler分析dump文件_内存溢出+CPU占用过高:问题排查+解决方案+复盘(超详细分析教程)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python网络爬虫的论文模板_Pyth
- 下一篇: js修改地址栏url_在gulp、cre