前言
????其實這個問題在我負責的項目里面已經(jīng)出現(xiàn)過一次了,但由于第一次出現(xiàn)并解決的時候我并不負責這個項目,導致印象不是很深,但沒有想到今天在測試環(huán)境又復現(xiàn)了,于是我相當于又重復了一遍之前的排查過程,當然也請教了其他的同事,所以我覺得有必要記錄下來(事不過三,還是沒有記?。菜闶且淮蜧C問題排查的經(jīng)驗了。
問題發(fā)生
? ? 大概11點30左右,有同事給我反饋是調用我的服務陸續(xù)開始有readTime out 產(chǎn)生,導致測試環(huán)境整體數(shù)據(jù)查詢失敗,QA無法進行測試,讓我?guī)兔μ幚硪幌?,于是我登錄上QA的測試機,準備查看一下服務狀態(tài)。
access日志
? ? 先查看了一下tomcat的access日志發(fā)現(xiàn)10點40之后服務就不對外響應了,第一時間感覺應該是服務僵死了,然后開始排查GC狀態(tài)。

GC排查
? ? ? 1.jstat -gcutil pid 1000
? ? ? ? ? ? 稍微解釋一下這個命令 每隔1秒打印當前jvm進程的內存分配占比及gc信息?,發(fā)現(xiàn)GC信息停滯,整個GC進程已經(jīng)不工作了,于是我認為可能是由于full GC的問題導致stop the world 使GC過程緩慢(當時詢問了一下同事,正巧QA同事在進行大數(shù)據(jù)量下載測試),于是我決定導出當前dump信息進行分析
? ? ? 2.jmap -dump:format=b,file=xxx.hprof pid?
? ? ? ? ? ? 發(fā)現(xiàn)連接不上,于是使用-F 強制dump,dump開始進行,但進行到一半左右,報出異常

?發(fā)現(xiàn)dump不下來之后,查了一下異常信息,發(fā)現(xiàn)很多說是由于JDKbug引起,但感覺沒有一個人說明白到底是為什么(這個我沒有查出來原因,歡迎大家給出方案,我也會繼續(xù)查一下),dump失敗之后我決定先看一下是否有線程hang住,于是用jstack查看。
3.jstack -F pid?
? ? 發(fā)現(xiàn)除了socket線程之后,其他線程都blocked,感覺這個問題還是沒有定位,決心繼續(xù)dump內存信息(其實這個時候思想已經(jīng)出問題了,正確做法是這個時候應該使用top查看是不是有線程占用了cpu導致其他線程無法繼續(xù)運行)

但是dump信息一直導不出來,到了這個時候有點懵圈了 三板斧打完,沒了,此時已經(jīng)是午飯過后(公司吃飯比較早 當然是先吃完飯了再回來排查),一看時間已經(jīng)2點20左右了,此時QA同學又開始催了,本著要弄明白再重啟的決心,我決定場外求助大佬,正巧一個大佬過來商量工作,于是在商量完之后果斷向他請教這個問題,大佬看完dump不下來之后認為是JDK出現(xiàn)的bug(不要問我為什么 我也不知道為什么),于是問我能不能使用jstack,我說可以,然后大佬決定先用TOP查看一下機器的資源使用情況。
?4.top?
? ? 先使用top命令發(fā)現(xiàn)當前僵死進程占用cpu 99.9%,? ? 然后跟上?top -H -p 發(fā)現(xiàn)有一個線程占用cpu高達98以上,于是感覺是這個線程的問題

5.pstack
? ? pstack 26846(僵死的進程號) 查看進程的線程信息 發(fā)現(xiàn)該線程為jvm線程而非業(yè)務線程,此時大佬給我說這是JDK的一個bug,具體原因他忘記了,這邊有個同事之前遇見過,這個bug會使類卸載失敗,從而導致cpu100%空轉,這個時候我突然想起之前聽同事說過以前我們項目出現(xiàn)過這個問題,當時公司一位大佬幫忙排查并解決之后,還在公司的微信公眾號發(fā)表了一篇文章,于是感覺去看了一下,發(fā)現(xiàn)原因一模一樣,這邊QA同學將之前出問題的jvm啟動配置原封不動的copy過來,然后啟動了我的服務(所以問題歸納總結感覺還是很有必要)

問題原因及解決
????這個圖我是從大佬的文章中拿的,因為我在解決問題的時候 并沒有保存之前的配置,所以就用了這個圖表達了,但是這2個服務配置是一模一樣的,出問題的服務就是從這個服務copy的配置。

? ? ? Xms? 初始化堆內存大小
? ? ? Xmx 最大堆內存大小 (大小設置為一樣可防止JVM動態(tài)調整影響運行時性能)
? ? ? Xmn 新生代大?。ü俜酵扑]位 3/8 )
? ? ? MetaSpaceSize 初始化元數(shù)據(jù)區(qū)大小
? ? ? MaxMetaSpaceSize? 元數(shù)據(jù)區(qū)最大大小
? ? ? noclassgc 不進行類卸載
? ? ? UseConcMarkSweep 使用cms進行老年代gc (附帶 jdk8中使用cms的時候 新生代默認為parNew)
? ? 上面指定了noclassgc 即不進行類卸載,但是在JDK中還有一個參數(shù)也可以指定是否進行類卸載即
?? ?CMSClassUnloadingEnable,而且在JDK8之后默認該參數(shù)為true 即進行類卸載,所以當同時指定這2個參數(shù)會發(fā)生類卸載失敗的情況(在特定版本中 如8u40),解決的辦法也很簡單 即不設置noclassgc即可,當然如果你想使用這個參數(shù)的話 建議升級JDK版本,在8u60之后 問題已經(jīng)解決,當它設置為false的時候cmsClassUnloadingEnable也會默認設置為false,保證處于同一邏輯下。
? ? 問題解決方案及原因參照我司JAVA大佬的博客-感興趣的可以微信公眾號 -貝殼產(chǎn)品技術 文章為《謎!JVM為何僵死》
總結? ?
? ? 其實之前也排查過一些簡單的gc問題 但是感覺這方面積累還不夠,加上自己水平還是比較菜(對,所以我的名字就叫菜菜子),處理一個問題還是需要很久,而且對知識總結較少,之后也會慢慢開始做一些總結性的東西,其實簡書我也開通很久了,也是第一篇文章,加油吧,777777(就這樣吧 ,我感覺就這樣)。? ??