摘自:http://dikar.javaeye.com/blog/643436
如題,我這里簡(jiǎn)單說(shuō)下我現(xiàn)在離線分析java內(nèi)存的方式,所謂離線,就是需要dump出正在運(yùn)行的java系統(tǒng)中的一些運(yùn)行時(shí)堆棧數(shù)據(jù),然后拿到線下來(lái)分析,分析可以包括內(nèi)存,線程,GC等等,同時(shí)不會(huì)對(duì)正在運(yùn)行的生產(chǎn)環(huán)境的機(jī)器造成很大的影響,對(duì)應(yīng)著離線分析,當(dāng)然是在線分析了,這個(gè)我在后面會(huì)嘗試下,因?yàn)殡x線分析有些場(chǎng)景還是模擬不出來(lái),需要借助LR來(lái)模擬壓力,查看在線的java程序運(yùn)行情況了。
首先一個(gè)簡(jiǎn)單的問(wèn)題,如何dump出java運(yùn)行時(shí)堆棧,這個(gè)SUN就提供了很好的工具,位于JAVA_HOME/bin目錄下的jmap(java memory map之意),如果需要dump出當(dāng)前運(yùn)行的java進(jìn)程的堆棧數(shù)據(jù),則首先需要獲得該java進(jìn)程的進(jìn)程ID,在linux下可以使用
- ps -aux
- ps -ef | grep java
或者使用jdk自帶的一個(gè)工具jps,例如
- /JAVA_HOME/bin/jps
找到了當(dāng)前運(yùn)行的java進(jìn)程的id后,就可以對(duì)正在運(yùn)行的java進(jìn)程使用jmap工具進(jìn)行dump了,例如使用以下命令:
- JAVA_HOME/bin/jmap -dump:format=b,file=heap.bin <pid>
其中file = heap.bin的意思是dump出的文件名叫heap.bin, 當(dāng)然你可以選擇你喜歡的名字,我這里選擇叫*.bin是為了后面使用方便,<pid>表示你需要dump的java進(jìn)程的id。
這里需要注意的是,記住dump的進(jìn)程是java進(jìn)程,不會(huì)是jboss的進(jìn)程,weblogic的進(jìn)程等。dump過(guò)程中機(jī)器load可能會(huì)升高,但是在我這里測(cè)試發(fā)現(xiàn)load升的不是特別快,同時(shí)dump時(shí)需要的磁盤空間也比較大,例如我這里測(cè)試的幾個(gè)系統(tǒng),分別是500M 800M 1500M 3000M,所以確保你運(yùn)行jmap命令時(shí)所在的目錄中的磁盤空間足夠,當(dāng)然現(xiàn)在的系統(tǒng)磁盤空間都比較大。
以上是在java進(jìn)程還存活的時(shí)候進(jìn)行的dump,有的時(shí)候我們的java進(jìn)程crash后,會(huì)生成一個(gè)core.pid文件,這個(gè)core.pid文件還不能直接被我們的java 內(nèi)存分析工具使用,需要將其轉(zhuǎn)換為java 內(nèi)存分析工具可以讀的文件(例如使用jmap工具dump出的heap.bin文件就是很多java 內(nèi)存分析工具可以讀的文件格式)。將core.pid文件轉(zhuǎn)換為jmap工具dump出的文件格式還可以繼續(xù)使用jmap工具,這個(gè)的說(shuō)明可以見(jiàn)我前幾篇中的一個(gè)轉(zhuǎn)載(Create Java heapdumps with the help of core dumps ),這里我在補(bǔ)充點(diǎn)
- jmap -heap:format=b [java binary] [core dump file]
- jmap -dump:format=b,file=dump.hprof [java binary] [core dump file]
- 64位下可以指定使用64位模式
- jmap -d64 -dump:format=b,file=dump.hprof [java binary] [core dump file]
需要說(shuō)明一下,使用jmap轉(zhuǎn)換core.pid文件時(shí),當(dāng)文件格式比較大時(shí),可能大于2G的時(shí)候就不能執(zhí)行成功(我轉(zhuǎn)換3G文件大小的時(shí)候沒(méi)有成功)而報(bào)出
Error attaching to core file: Can't attach to the core file
查過(guò)sun的bug庫(kù)中,這個(gè)bug還沒(méi)有被修復(fù),我想還是由于32位下用戶進(jìn)程尋址大小限制在2G的范圍內(nèi)引起的,在64位系統(tǒng)和64位jdk版本中,轉(zhuǎn)換3G文件應(yīng)該沒(méi)有什么大的問(wèn)題(有機(jī)會(huì)有環(huán)境得需要測(cè)試下)。如果有興趣分析jmap轉(zhuǎn)換不成功的同學(xué),可以使用如下命令來(lái)分析跟蹤命令的執(zhí)行軌跡,例如使用
- strace jmap -heap:format=b [java binary] [core dum
對(duì)于strace的命令的說(shuō)明,同樣可以參考我前幾篇文章中的一個(gè) strace命令用法
同時(shí)對(duì)于core.pid文件的調(diào)試我也補(bǔ)充一下, 其中>>表示命令提示符
- >>gdb JAVA_HOME/bin/java core.pid
- >>bt
bt后就可以看到生成core.pid文件時(shí),系統(tǒng)正在執(zhí)行的一個(gè)操作,例如是哪個(gè)so文件正在執(zhí)行等。
好了說(shuō)了這么多,上面都是怎么生成java 運(yùn)行期DUMP文件的,接下來(lái)我們就進(jìn)入分析階段,為了分析這個(gè)dump出的文件,需要將這個(gè)文件弄到你的分析程序所在的機(jī)器上,例如可以是windows上,linux上,這個(gè)和你使用的分析工具以及使用的操作系統(tǒng)有關(guān)。不管使用什么系統(tǒng),總是需要把生產(chǎn)環(huán)境下打出的dump文件搞到你的分析機(jī)器上,由于dump出的文件經(jīng)常會(huì)比較大,例如達(dá)到2G,這么大的文件不是很好的從生產(chǎn)環(huán)境拉下來(lái),因此使用FTP的方式把文件拖到分析機(jī)器上,同時(shí)由于單個(gè)文件很大,因此為了快速的將文件下載到分析機(jī)器,我們可以使用分而治之的思想,先將文件切割為小文件下載,然后在合并為一個(gè)大文件即可,還好linux提供了很方便的工具,例如使用如下命令
- $ split -b 300m heap.bin
- $ cat x* > heap.bin
在上面的 split 命令行中的 “300m” 表示分割后的每個(gè)文件為 300MB,“heap.bin” 為待分割的dump文件,分割后的文件自動(dòng)命名為 xaa,xab,xac等
cat 命令可將這些分割后的文件合并為一個(gè)文件,例如將所有x開(kāi)頭的文件合并為heap.bin
如果我們是利用一個(gè)中間層的FTP服務(wù)器來(lái)保存數(shù)據(jù)的,那么我們還需要連接這個(gè)FTP服務(wù)器把合并后的文件拉下來(lái),在windows下我推薦使用一個(gè)工具,速度很快而且簡(jiǎn)單,
winscp http://winscp.net/eng/docs/lang:chs
好了分析的文件終于經(jīng)過(guò)一翻周折到了你的分析機(jī)器上,現(xiàn)在我們就可以使用分析工具來(lái)分析這個(gè)dump出的程序了,這里我主要是分析內(nèi)存的問(wèn)題,所以我說(shuō)下我選擇的內(nèi)存分析工具,我這里使用的是開(kāi)源的由SAP 和IBM 支持的一個(gè)內(nèi)存分析工具
Memory Analyzer (MAT)
http://www.eclipse.org/mat/
我建議下載 Stand-alone Eclipse RCP 版本,不要裝成eclipse的插件,因?yàn)檫@個(gè)分析起來(lái)還是很耗內(nèi)存。
下載好了,解壓開(kāi)來(lái)就可以直接使用了(基于eclipse的),打開(kāi)以后,在菜單欄中選擇打開(kāi)文件,選擇你剛剛的dump文件,然后一路的next就可以了,最后你會(huì)看到一個(gè)報(bào)告,這個(gè)報(bào)告里會(huì)告訴你可能的內(nèi)存泄露的點(diǎn),以及內(nèi)存中對(duì)象的一個(gè)分布,關(guān)于mat的使用請(qǐng)參考官方說(shuō)明,當(dāng)然你也可以自己徜徉在學(xué)習(xí)的海洋中 。
對(duì)于dump文件的分析還可以使用jdk中提供的一個(gè)jhat工具來(lái)查看,不過(guò)這個(gè)很耗內(nèi)存,而且默認(rèn)的內(nèi)存大小不夠,還需要增加參數(shù)設(shè)置內(nèi)存大小才能分析出,不過(guò)我看了下分析出的結(jié)果不是很滿意,而且這個(gè)用起來(lái)很慢。還是推薦使用mat 。