JAVA應(yīng)用頻繁GC問(wèn)題排查過(guò)程
頻繁GC背景
處理過(guò)線(xiàn)上問(wèn)題的同學(xué)基本上都會(huì)遇到系統(tǒng)突然運(yùn)行緩慢,CPU 100%,以及Full GC次數(shù)過(guò)多的問(wèn)題。當(dāng)然,這些問(wèn)題的最終導(dǎo)致的直觀現(xiàn)象就是系統(tǒng)運(yùn)行緩慢,并且有大量的報(bào)警。
本文主要記一次針對(duì)系統(tǒng)頻繁GC這一問(wèn)題,提供該問(wèn)題的排查思路,從而定位出問(wèn)題的代碼點(diǎn),進(jìn)而提供解決該問(wèn)題的思路。
不再重復(fù)贅述網(wǎng)上大部分排查GC命令,工具使用或者GC本身定義等
問(wèn)題描述
發(fā)現(xiàn)商品應(yīng)用product-dubbo頻繁GC告警
規(guī)則名稱(chēng): 【性能告警】應(yīng)用GC次數(shù)大于20次/分鐘(且新生代GC時(shí)間大于50ms) 觸發(fā)時(shí)值: 74 監(jiān)控指標(biāo): [AlarmName=GC次數(shù) application=product-dubbo ...] 持續(xù)時(shí)長(zhǎng): 0s 觸發(fā)時(shí)間: 2025-06-21 11:44:06
同時(shí)有慢接口告警
規(guī)則名稱(chēng): 【嚴(yán)重性能告警】應(yīng)用接口平均響應(yīng)時(shí)間大于1s 觸發(fā)時(shí)值: 2.4098 規(guī)則備注: 過(guò)去十分鐘內(nèi)的平均響應(yīng)時(shí)間 監(jiān)控指標(biāo): [AlarmName=接口RT application=product-client uri=/api/product/client/list] 持續(xù)時(shí)長(zhǎng): 0s 觸發(fā)時(shí)間: 2025-06-21 11:03:39
問(wèn)題排查思路
對(duì)于線(xiàn)上系統(tǒng)突然出現(xiàn)頻繁GC問(wèn)題,這種情況可能的原因主要有:代碼中某個(gè)位置讀取數(shù)據(jù)量較大,導(dǎo)致系統(tǒng)內(nèi)存耗盡,從而導(dǎo)致Full GC次數(shù)過(guò)多,那么首先需要做的就是,導(dǎo)出dump堆棧文件,分析其具體的內(nèi)存信息
使用線(xiàn)程轉(zhuǎn)儲(chǔ)(Thread Dump)分析工具:
鏈接: link
其中等待線(xiàn)程數(shù)558,超時(shí)等待線(xiàn)程數(shù)49,運(yùn)行線(xiàn)程數(shù)44

未發(fā)現(xiàn)消耗CPU的線(xiàn)程和阻塞線(xiàn)程

同時(shí)也沒(méi)有死鎖線(xiàn)程

排除掉異常線(xiàn)程導(dǎo)致頻繁gc問(wèn)題
進(jìn)一步分析線(xiàn)程池里包含的線(xiàn)程

其中dubbo線(xiàn)程占據(jù)90%,其余線(xiàn)程比如tomcat線(xiàn)程,logback線(xiàn)程,自定義線(xiàn)程池線(xiàn)程等只占一小部分
排查dubbo線(xiàn)程堆棧發(fā)現(xiàn)問(wèn)題

出現(xiàn)mysql存在異常

同時(shí)存在druid超時(shí)線(xiàn)程
綜合分析
dubbo線(xiàn)程調(diào)用方法里面出現(xiàn)mysql異常,結(jié)合告警的慢接口是同一處,懷疑是否是慢sql導(dǎo)致的數(shù)據(jù)庫(kù)連接池druid打滿(mǎn),進(jìn)而導(dǎo)致dubbo大部分線(xiàn)程處于等待狀態(tài)
通過(guò)arthas分析本次告警的慢接口
trace com.biz.prooduct queryList '#cost > 100'

進(jìn)一步驗(yàn)證上述分析結(jié)論
通過(guò)arthas分析內(nèi)存對(duì)象
dumpheap --live /tmp/dump.hprof'
打開(kāi)本地jvm分析工具分析hprof文件如下:

發(fā)現(xiàn)堆中占內(nèi)存前三位的分別是char[]、String 和 ConcurrentHashMap$Node三個(gè)類(lèi)其中char[]占用絕大部分空間,進(jìn)一步分析char[]數(shù)據(jù):

上述char[]中存放的基本都是/api/product/client/list返回的數(shù)據(jù)
綜合分析
由于/api/product/client/list是客戶(hù)端獲取商品列表接口,客戶(hù)端每次查詢(xún)商品都會(huì)去掉用,存在大量并發(fā)的場(chǎng)景,并且接口方法內(nèi)部是拉取全量商品數(shù)據(jù)。
同時(shí)該接口有數(shù)次慢sql的代碼,慢SQL進(jìn)一步導(dǎo)致數(shù)據(jù)庫(kù)連接池耗盡,進(jìn)而阻塞Dubbo線(xiàn)程的典型故障鏈,從而引發(fā)頻繁GC。
解決方案
1.慢sql優(yōu)化(通過(guò)執(zhí)行計(jì)劃按量?jī)?yōu)化索引等)
2.方法優(yōu)化(異步處理非核心代碼)
3.業(yè)務(wù)優(yōu)化(監(jiān)聽(tīng)商品變動(dòng)方法,客戶(hù)端拉取全量商品存在本地,商品發(fā)生變動(dòng)通知客戶(hù)端重新拉取商品)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java Swing實(shí)現(xiàn)JTable檢測(cè)單元格數(shù)據(jù)變更事件的方法示例
這篇文章主要介紹了Java Swing實(shí)現(xiàn)JTable檢測(cè)單元格數(shù)據(jù)變更事件的方法,結(jié)合完整實(shí)例形式分析了Swing實(shí)現(xiàn)JTable檢測(cè)單元格數(shù)據(jù)變更事件過(guò)程中出現(xiàn)的問(wèn)題與相關(guān)解決方法,需要的朋友可以參考下2017-11-11
Spring如何解決單例bean線(xiàn)程不安全的問(wèn)題
這篇文章主要介紹了Spring如何解決單例bean線(xiàn)程不安全的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
Spring IOC創(chuàng)建對(duì)象的兩種方式
這篇文章主要給大家介紹了關(guān)于Spring IOC創(chuàng)建對(duì)象的兩種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
從零搭建SpringCloud的超詳細(xì)過(guò)程
本文給大家詳細(xì)介紹從零搭建SpringCloud的超詳細(xì)過(guò)程,本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-09-09
Java中StringBuilder與StringBuffer的區(qū)別
在Java編程中,字符串的拼接是一項(xiàng)常見(jiàn)的操作。為了有效地處理字符串的拼接需求,Java提供了兩個(gè)主要的類(lèi):StringBuilder和StringBuffer,本文主要介紹了Java中StringBuilder與StringBuffer的區(qū)別,感興趣的可以了解一下2023-08-08
基于maven的springboot的"過(guò)時(shí)"用法解析
這篇文章主要為大家介紹了基于maven的springboot"過(guò)時(shí)"用法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
為SpringBoot服務(wù)添加HTTPS證書(shū)的方法
這篇文章主要介紹了為SpringBoot服務(wù)添加HTTPS證書(shū)的方法,幫助大家更好的理解和使用springBoot框架,感興趣的朋友可以了解下2020-10-10

