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