一、 問(wèn)題描述
最近在正常的版本迭代過(guò)程中,開(kāi)發(fā)代碼已正常交付測(cè)試,結(jié)果有一天,測(cè)試反應(yīng),測(cè)試環(huán)境響應(yīng)很慢,系統(tǒng)卡,讓開(kāi)發(fā)找下原因.
二、 開(kāi)發(fā)介入
首先現(xiàn)階段只有生產(chǎn)和預(yù)生產(chǎn)環(huán)境,有專門的監(jiān)控工具,可以很方便的定位到CPU占比較高的線程和對(duì)應(yīng)的慢sql,或者慢響應(yīng)。不過(guò)SIT環(huán)境并沒(méi)有這些工具,所以需要我們自己手動(dòng)介入了。要了測(cè)試機(jī)器的賬戶和密碼,首先看到的現(xiàn)象如下
Linux指令:
1>ps –ef | grep java
2>top –d 1

這里看到cpu直接彪到179%,為了避免是瞬時(shí)升高,我們監(jiān)控了兩分鐘左右,持續(xù)在這個(gè)比值??赡軙?huì)很奇怪,cpu怎么會(huì)超過(guò)100%,這里其實(shí)統(tǒng)計(jì)的是cpu的總利用率,原因在于,我們的機(jī)器是2C,所以是進(jìn)行累計(jì)求和的。
三、 javacore 和 heapdump文件的區(qū)別
java程序在運(yùn)行時(shí),當(dāng)遇到致命問(wèn)題時(shí),jvm會(huì)在java進(jìn)程掛掉之前產(chǎn)生兩個(gè)文件,一個(gè)是javacore,一個(gè)是heapdump文件
兩者的區(qū)別:
JavaCore文件主要保存的是Java應(yīng)用各線程在某一時(shí)刻的運(yùn)行的位置,即JVM執(zhí)行到哪一個(gè)類、哪一個(gè)方法、哪一個(gè)行上。它是一個(gè)文本文件,打開(kāi)后可以看到每一個(gè)線程的執(zhí)行棧,以stack trace的顯示。通過(guò)對(duì)JavaCore文件的分析可以得到應(yīng)用是否“卡”在某一點(diǎn)上,即在某一點(diǎn)運(yùn)行的時(shí)間太長(zhǎng),例如數(shù)據(jù)庫(kù)查詢,長(zhǎng)期得不到響應(yīng),最終導(dǎo)致系統(tǒng)崩潰等情況
HeapDump文件是一個(gè)二進(jìn)制文件,它保存了某一時(shí)刻JVM堆中對(duì)象使用情況,這種文件需要相應(yīng)的工具進(jìn)行分析,如Jdk自帶工具Jvisual VM、IBM Heap Analyzer這類工具。這類文件最重要的作用就是分析系統(tǒng)中是否存在內(nèi)存溢出的情況
如下圖:javacore文件部分截圖

dump 文件由于是二進(jìn)制文件,我們只是看下文件后綴名

四、 手動(dòng)拉取heapdump文件
結(jié)合我們的實(shí)際問(wèn)題,上述兩個(gè)文件我們其實(shí)都需要,雖然說(shuō)是heapdump是用來(lái)分析堆內(nèi)存的,但是如果頻繁fgc,cpu的使用率必然也會(huì)居高不下

第二種方式:是JVM會(huì)幫我們自己生成,當(dāng)我們的機(jī)器在頻繁FGC的時(shí)候,會(huì)自動(dòng)觸發(fā)產(chǎn)生dump文件。
我們先來(lái)看下當(dāng)時(shí)頻繁FGC時(shí)的現(xiàn)狀,下圖我們重點(diǎn)關(guān)注老年代的使用率和FGC的次數(shù),這里我們監(jiān)控頻率是3s

jstat -gc 1186 3000 該指令可以看到具體的分代大小,和每次回收大小

這里我們使用的G1收集器
注意點(diǎn):通常dump文件是非常大的,如果用這種方式生成的文件大小都有幾個(gè)G甚至十幾個(gè)G,這種文件我們通過(guò)ftp下載本地,進(jìn)行分析,是非常困難。所以在生成文件大小時(shí),可以去指定大小
五、 JavaCore文件分析
JavaCore文件上述我們可以看到,其實(shí)單單看文件,是比較痛苦,因?yàn)檫@里會(huì)羅列出每個(gè)線程的執(zhí)行狀態(tài),對(duì)于我們定位問(wèn)題的效率是很慢的
所以我們需要重點(diǎn)關(guān)注當(dāng)前哪個(gè)線程的CPU占比最高,這是發(fā)現(xiàn)問(wèn)題的關(guān)鍵。通常我們用自研工具或者三方工具來(lái)去統(tǒng)計(jì),舉一個(gè)跟本專題不相關(guān)的例子

六、 Heapdump文件分析
這里我們使用工具M(jìn)emoryAnalyzer工具來(lái)進(jìn)行分析,為什么不用jdk自帶的jvisualvm

個(gè)人感覺(jué):這個(gè)工具結(jié)合visualGC插件來(lái)分析實(shí)時(shí)應(yīng)用的堆內(nèi)存使用情況還是比較直觀


言歸正傳,進(jìn)入我們今天的主角
導(dǎo)入dump文件之后

這里說(shuō)名下,標(biāo)色的是我們應(yīng)用所占用堆內(nèi)存最大的對(duì)象集
以下是我們最常用的分析統(tǒng)計(jì)工具,紅框分別表示:直視圖、樹(shù)視圖,直視圖統(tǒng)計(jì)了大對(duì)象里占用最大的基本類型,還是不夠直觀。所以我們用樹(shù)視圖

樹(shù)視圖打開(kāi)如下:

Shallow heap:對(duì)象自身占用的內(nèi)存大小,不包括引用
Retained heap:表示當(dāng)前對(duì)象被GC之后,從堆上總共釋放的掉的內(nèi)存
Percentage:占用百分比
這里的單位表示字節(jié)大小。由第一行我們看到,是于數(shù)據(jù)庫(kù)相關(guān)的,關(guān)鍵字ResultSet,說(shuō)明當(dāng)前操作數(shù)據(jù)庫(kù)的線程本身大小176字節(jié),但是被GC掉后,可以回收342684112字節(jié)的內(nèi)存,這下我們可以大膽的推斷:應(yīng)該是查了很多數(shù)據(jù)。

上圖可以確定是一個(gè)數(shù)據(jù)量很大的list
進(jìn)一步確認(rèn):打開(kāi)第二個(gè)線程,結(jié)果已經(jīng)出來(lái)了,里面已經(jīng)標(biāo)出我們對(duì)應(yīng)的sql和調(diào)用點(diǎn)

將sql抽取出來(lái),發(fā)現(xiàn)是全表掃描,該表目前的數(shù)據(jù)量是14萬(wàn),而我們生產(chǎn)實(shí)際有600多萬(wàn),生產(chǎn)上線必炸,通過(guò)代碼修改,cpu使用率恢復(fù)正常
七、 總結(jié)
以上分析是對(duì)于我們?cè)贈(zèng)]有使用比較高級(jí)的javacore 和 dump文件分析工具時(shí),自己去手動(dòng)拉取文件自己去分析。在大型互聯(lián)網(wǎng)公司里,各自都有自己的分析工具。比如業(yè)界比較流行的就是阿里的在線分析診斷工具Arthas

.