一次JVM_OLD區佔用過高、頻繁Full GC的解決過程
最近,公司網站頻繁報警,JVM_OLD佔用過高,線上訪問超時嚴重,針對這個問題著實頭疼了一把,不過最終還是解決了,下面說下解決的過程。
1,首先 登到線上機器上去,top命令,檢視當前機器的負載,檢視當前哪個程式在消耗資源。
Shell
1 |
top |
找到CPU或者記憶體佔用過高的那個程式。發現有一個程式,CPU居高不下,保留程式id
2,top命令,繼續跟蹤該程式裡的所有執行緒,找到佔用CPU過高的執行緒。
Shell
1 |
top -Hp [程式ID] |
3,找到執行緒ID,正在消耗CPU,把執行緒ID轉換為16進位制,執行jstack命令保留當前java程式堆疊
Shell
1 |
jstack [程式ID] > jstack_01 |
然後,在該檔案jstack_01 裡搜尋 執行緒id為[16進位制的執行緒id]的執行緒,檢視堆疊資訊。
一般情況下,這三部就能找到消耗資源的執行緒的情況,看到該執行緒的執行堆疊資訊,當時發現,其實中 nid=0x8d0f 的執行緒在佔用cpu,堆疊裡看到的是VM執行緒,VM執行緒的意思就是jvm執行緒在工作,看下面幾個run的執行緒,都是gc執行緒,猜測,此時,jvm正在GC。
4、接下來就是確認當前JVM各分割槽的情況了,這裡使用的是jstat
Shell
1 |
jstat -gcutil [程式id] 1000 |
每1000ms列印一次gc資訊。
通過此圖,可以發現,新生代eden區,survivor區,old區都已經100%,並且,jvm啟動到現在,Full GC了978次,共花費時間12240.255秒,這樣平均每次Full GC 12.5秒。
看來就是Full GC頻繁並且過程漫長,導致線上機器卡死的問題了。下面解釋下jstat的gc資訊各個欄位的含義:
Shell
1 2 3 4 5 6 7 8 9 10 |
S0 年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比 S1 年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比 E 年輕代中Eden(伊甸園)已使用的佔當前容量百分比 O old代已使用的佔當前容量百分比 P perm代已使用的佔當前容量百分比 YGC 從應用程式啟動到取樣時年輕代中gc次數 YGCT 從應用程式啟動到取樣時年輕代中gc所用時間(s) FGC 從應用程式啟動到取樣時old代(全gc)gc次數 FGCT 從應用程式啟動到取樣時old代(全gc)gc所用時間(s) GCT 從應用程式啟動到取樣時gc用的總時間(s) |
5、確認是Full GC問題,那就只能看堆記憶體了,
Shell
1 |
jmap -histo [程式id] > jmap.txt |
該命令可以檢視當前jvm記憶體裡物件的例項數和佔用記憶體數
【注意】該命令可能會造成線上程式假死,會卡死一段時間,所以線上程式謹慎使用!!!
從結果裡可以看出,佔記憶體最多的是前兩個,一個是char,一個是string
所以有以下猜測:
1)程式裡有記憶體快取,快取的是字串,記憶體快取逐漸增多,逐步移步老年代,最終導致爆滿。
2)有大量拼接字串的地方,
3)static的變數,儲存大量的字串,排名第六的是hashMap,猜想可能是有static的 hashMap??
繼續分析該檔案,看到,有個 com.bj58.jwdf.framework.cache.ConcurrentCacheProvider 物件,有10w多個例項,通過看程式碼,的確這個是一個自己實現的記憶體快取,果斷想辦法優化。
優化上線後,發現記憶體問題雖然有所緩解,但是還是會有jvm爆滿的時候。
這樣在繼續分析,就比較困難了,然後同時優化了下jvm啟動的引數,新增full gc的時機,
Shell
1 |
-XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly |
保證,在old區達到80%的時候就開始執行Full GC。
新增:
Shell
1 |
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log |
列印gc資訊,以便保留證據。
並且在程式碼裡查詢一些其他的公共的static 的map 以及 記憶體快取的地方,統統優化了,上線後還是不理想。
最後沒辦法了,只能dump堆記憶體快照了,用工具分析了。
修改jvm啟動記憶體,改小一些,以便在滿的時候打的快照能在本地分析,,
Shell
1 |
jmap -dump:format=b,file=aa.bin 1232134 |
改命令列印出堆記憶體快照,我把jvm記憶體改成最大6G,下載的快照檔案,足足有6.5G,然後下載MAT工具進行分析。
相關文章
- 頻繁GC (Allocation Failure)及young gc時間過長分析GCAI
- mysql佔用CPU過高的解決辦法(新增索引)MySql索引
- 線上排查:記憶體異常使用導致full gc頻繁記憶體GC
- 電腦記憶體佔用過高怎麼辦 電腦記憶體佔用過高解決方法記憶體
- 一次JVM GC長暫停的排查過程!JVMGC
- 一次JVM GC長暫停的排查過程JVMGC
- 一次對pool的誤用導致的.net頻繁gc的診斷分析GC
- 一次sqlldr匯入慢的解決過程SQL
- 記一次 Composer 問題的解決過程!!
- 一次線上問題的排查解決過程
- [React]setState呼叫過於頻繁的問題React
- 記一次使用gdb診斷gc問題全過程GC
- .記一次使用gdb診斷gc問題全過程GC
- 記一次透過Memory Analyzer分析記憶體洩漏的解決過程記憶體
- 記一次用Android Studio的Profiler排查安卓記憶體佔用過高Android安卓記憶體
- Full GC (Metadata GC Threshold)GC
- win10工作管理員記憶體佔用過高怎麼解決Win10記憶體
- 記錄一次排查解決伺服器卡死的過程伺服器
- Win10系統下火狐瀏覽器佔用CPU過高的解決方法Win10瀏覽器
- Go語言高併發與微服務實戰專題精講——遠端過程呼叫 RPC——最佳化RPC呼叫,緩解頻繁請求導致的GC壓力Go微服務RPC求導GC
- RabbitMQ 處理過慢,原來是一個 SQL 快取框架導致的 GC 頻繁觸發MQSQL快取框架GC
- win10 2004系統cpu佔用高怎麼辦_win10 2004系統佔用cpu過高解決教程Win10
- 記一次bug解決過程(數字轉化成中文)
- java應用CPU佔用率過高排查Java
- 一次FGC導致CPU飆高的排查過程GC
- GitHub 近期頻繁當機?官方解釋:MySQL 負載過重GithubMySql負載
- 一次難忘的協助解決Oracle RAC恢復過程Oracle
- 詳細記錄一次npm i canvas報錯的解決過程NPMCanvas
- win10開機cpu高佔用怎麼解決 win10電腦一開機cpu佔用過高處理方法Win10
- GC析構物件和列表的處理過程GC物件
- 記一次asp.net 8 伺服器爆滿的解決過程ASP.NET伺服器
- 一個 ExpressionChangedAfterItHasBeenCheckedError 錯誤的解決過程ExpressError
- 通過禁用MSI模式解決Win10磁碟佔用100%的方法模式Win10
- 透過禁用MSI模式解決Win10磁碟佔用100%的方法模式Win10
- win10系統defender antivirus cpu佔用率過高怎麼解決Win10
- 弄清Java虛擬機器GC的執行過程Java虛擬機GC
- oracle RDBMS Kernel Executable 佔用記憶體過高Oracle記憶體
- 應用儲存過程執行報錯解決方案儲存過程